手机探索者开发实录—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. staticrfbScreenInfoPtrrfb_screen=NULL;
  2. staticCoreInputDevice*vncPointerDevice=NULL;
  3. staticCoreInputDevice*vncKeyboardDevice=NULL;
  4. staticintg_vnc_client_nr=0;

  5. typedefstruct_ClientData
  6. {
  7. intoldButtonMask;
  8. intpressed;
  9. intoldx;
  10. intoldy;
  11. }ClientData;

  12. staticvoidvnc_client_gone(rfbClientPtrcl);
  13. staticenumrfbNewClientActionvnc_client_new(rfbClientPtrcl);
  14. staticboolvnc_translate_key(rfbKeySymkey,DFBInputEvent*evt);
  15. staticvoid*vnc_server_thread(DirectThread*thread,void*data);
  16. staticvoid*vnc_refresh_thread(DirectThread*thread,void*data);
  17. staticvoidvnc_process_key_event(rfbBooldown,rfbKeySymkey,struct_rfbClientRec*cl);
  18. staticvoidvnc_process_pointer_event(intbuttonMask,intx,inty,struct_rfbClientRec*cl);
  19. staticDFBResultvnc_update_screen(unsignedshort*src,intx,inty,intw,inth);
  20. staticDFBResultvnc_set_video_mode(DFBDisplayLayerConfig*config);
  21. staticDFBEnumerationResultvnc_attach_keyboard_device(CoreInputDevice*device,void*ctx);
  22. staticDFBEnumerationResultvnc_attach_pointer_device(CoreInputDevice*device,void*ctx);

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

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

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

  13. returnDFENUM_OK;
  14. }
  15. staticvoidvnc_client_gone(rfbClientPtrcl)
  16. {
  17. g_vnc_client_nr--;
  18. free(cl->clientData);

  19. return;
  20. }

  21. staticenumrfbNewClientActionvnc_client_new(rfbClientPtrcl)
  22. {
  23. g_vnc_client_nr++;
  24. cl->clientData=(void*)calloc(sizeof(ClientData),1);
  25. cl->clientGoneHook=vnc_client_gone;
  26. returnRFB_CLIENT_ACCEPT;
  27. }


  28. staticvoid
  29. vnc_process_pointer_event(intbuttonMask,intx,inty,rfbClientPtrcl)
  30. {

  31. DFBInputEventevt={0};
  32. intbutton=0;

  33. if(vncPointerDevice==NULL){
  34. /*Attachtofirstinputdevice*/
  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. intmask=buttonMask^cd->oldButtonMask;
  42. if(mask&(1<<0)){
  43. button=DIBI_LEFT;
  44. }elseif(mask&(1<<1)){
  45. button=DIBI_MIDDLE;
  46. }elseif(mask&(1<<2)){
  47. button=DIBI_RIGHT;
  48. }else{
  49. return;
  50. }
  51. evt.flags=DIEF_NONE;
  52. if(cd->pressed)
  53. {
  54. evt.type=DIET_BUTTONRELEASE;
  55. cd->pressed=0;
  56. cd->oldButtonMask=0;
  57. }else{
  58. evt.type=DIET_BUTTONPRESS;
  59. cd->pressed=1;
  60. cd->oldButtonMask=buttonMask;
  61. }
  62. evt.button=button;
  63. printf("%s%d%d%d%d/n",__func__,button,cd->pressed,x,y);
  64. dfb_input_dispatch(vncPointerDevice,&evt);
  65. cd->oldx=x;
  66. cd->oldy=y;
  67. return;
  68. }

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

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

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

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

  85. }

  86. /*
  87. *declarationofprivatedata
  88. */
  89. staticvoid
  90. vnc_process_key_event(rfbBooldown,rfbKeySymkey,rfbClientPtrcl)
  91. {
  92. DFBInputEventevt;
  93. if(vncKeyboardDevice==NULL){
  94. /*Attachtofirstinputdevice*/
  95. dfb_input_enumerate_devices(vnc_attach_keyboard_device,NULL,DICAPS_KEYS);
  96. D_ASSERT(vncKeyboardDevice);
  97. }
  98. if(down)
  99. evt.type=DIET_KEYPRESS;
  100. else
  101. evt.type=DIET_KEYRELEASE;
  102. if(vnc_translate_key(key,&evt)){
  103. dfb_input_dispatch(vncKeyboardDevice,&evt);
  104. }

  105. }


  106. staticbool
  107. vnc_translate_key(rfbKeySymkey,DFBInputEvent*evt)
  108. {
  109. /*Unicode*/
  110. if(key<=0xf000){
  111. evt->flags=DIEF_KEYSYMBOL;
  112. evt->key_symbol=key;
  113. returntrue;
  114. }

  115. /*Deadkeys*/
  116. /*todo*/

  117. /*Numerickeypad*/
  118. if(key>=XK_KP_0&&key<=XK_KP_9){
  119. evt->flags=DIEF_KEYID;
  120. evt->key_id=DIKI_KP_0+key-XK_KP_0;
  121. returntrue;
  122. }

  123. /*Functionkeys*/
  124. if(key>=XK_F1&&key<=XK_F11){
  125. evt->flags=DIEF_KEYID;
  126. evt->key_id=DIKI_F1+key-XK_F1;
  127. returntrue;
  128. }

  129. switch(key){
  130. /*Numerickeypad*/
  131. caseXK_KP_Decimal:
  132. evt->flags=DIEF_KEYID;
  133. evt->key_id=DIKI_KP_DECIMAL;
  134. break;

  135. caseXK_KP_Separator:
  136. evt->flags=DIEF_KEYID;
  137. evt->key_id=DIKI_KP_SEPARATOR;
  138. break;

  139. caseXK_KP_Divide:
  140. evt->flags=DIEF_KEYID;
  141. evt->key_id=DIKI_KP_DIV;
  142. break;

  143. caseXK_KP_Multiply:
  144. evt->flags=DIEF_KEYID;
  145. evt->key_id=DIKI_KP_MULT;
  146. break;

  147. caseXK_KP_Subtract:
  148. evt->flags=DIEF_KEYID;
  149. evt->key_id=DIKI_KP_MINUS;
  150. break;

  151. caseXK_KP_Add:
  152. evt->flags=DIEF_KEYID;
  153. evt->key_id=DIKI_KP_PLUS;
  154. break;

  155. caseXK_KP_Enter:
  156. evt->flags=DIEF_KEYID;
  157. evt->key_id=DIKI_KP_ENTER;
  158. break;

  159. caseXK_KP_Equal:
  160. evt->flags=DIEF_KEYID;
  161. evt->key_id=DIKI_KP_EQUAL;
  162. break;


  163. /*Arrows+Home/Endpad*/
  164. caseXK_Up:
  165. evt->flags=DIEF_KEYID;
  166. evt->key_id=DIKI_UP;
  167. break;

  168. caseXK_Down:
  169. evt->flags=DIEF_KEYID;
  170. evt->key_id=DIKI_DOWN;
  171. break;

  172. caseXK_Right:
  173. evt->flags=DIEF_KEYID;
  174. evt->key_id=DIKI_RIGHT;
  175. break;

  176. caseXK_Left:
  177. evt->flags=DIEF_KEYID;
  178. evt->key_id=DIKI_LEFT;
  179. break;

  180. caseXK_Insert:
  181. evt->flags=DIEF_KEYID;
  182. evt->key_id=DIKI_INSERT;
  183. break;
  184. caseXK_Delete:
  185. evt->flags=DIEF_KEYID;
  186. evt->key_id=DIKI_DELETE;
  187. break;

  188. caseXK_Home:
  189. evt->flags=DIEF_KEYID;
  190. evt->key_id=DIKI_HOME;
  191. break;

  192. caseXK_End:
  193. evt->flags=DIEF_KEYID;
  194. evt->key_id=DIKI_END;
  195. break;

  196. caseXK_Page_Up:
  197. evt->flags=DIEF_KEYID;
  198. evt->key_id=DIKI_PAGE_UP;
  199. break;

  200. caseXK_Page_Down:
  201. evt->flags=DIEF_KEYID;
  202. evt->key_id=DIKI_PAGE_DOWN;
  203. break;


  204. /*Keystatemodifierkeys*/
  205. caseXK_Num_Lock:
  206. evt->flags=DIEF_KEYID;
  207. evt->key_id=DIKI_NUM_LOCK;
  208. break;

  209. caseXK_Caps_Lock:
  210. evt->flags=DIEF_KEYID;
  211. evt->key_id=DIKI_CAPS_LOCK;
  212. break;

  213. caseXK_Scroll_Lock:
  214. evt->flags=DIEF_KEYID;
  215. evt->key_id=DIKI_SCROLL_LOCK;
  216. break;

  217. caseXK_Shift_R:
  218. evt->flags=DIEF_KEYID;
  219. evt->key_id=DIKI_SHIFT_R;
  220. break;

  221. caseXK_Shift_L:
  222. evt->flags=DIEF_KEYID;
  223. evt->key_id=DIKI_SHIFT_L;
  224. break;

  225. caseXK_Control_R:
  226. evt->flags=DIEF_KEYID;
  227. evt->key_id=DIKI_CONTROL_R;
  228. break;

  229. caseXK_Control_L:
  230. evt->flags=DIEF_KEYID;
  231. evt->key_id=DIKI_CONTROL_L;
  232. break;

  233. caseXK_Alt_R:
  234. evt->flags=DIEF_KEYID;
  235. evt->key_id=DIKI_ALT_R;
  236. break;

  237. caseXK_Alt_L:
  238. evt->flags=DIEF_KEYID;
  239. evt->key_id=DIKI_ALT_L;
  240. break;

  241. caseXK_Meta_R:
  242. evt->flags=DIEF_KEYID;
  243. evt->key_id=DIKI_META_R;
  244. break;

  245. caseXK_Meta_L:
  246. evt->flags=DIEF_KEYID;
  247. evt->key_id=DIKI_META_L;
  248. break;

  249. caseXK_Super_L:
  250. evt->flags=DIEF_KEYID;
  251. evt->key_id=DIKI_SUPER_L;
  252. break;

  253. caseXK_Super_R:
  254. evt->flags=DIEF_KEYID;
  255. evt->key_id=DIKI_SUPER_R;
  256. break;

  257. caseXK_Hyper_L:
  258. evt->flags=DIEF_KEYID;
  259. evt->key_id=DIKI_HYPER_L;
  260. break;
  261. caseXK_Hyper_R:
  262. evt->flags=DIEF_KEYID;
  263. evt->key_id=DIKI_HYPER_R;
  264. break;

  265. /*case??:
  266. evt->flags=DIEF_KEYID;
  267. evt->key_id=DIKI_ALTGR;
  268. break;*/

  269. caseXK_BackSpace:
  270. evt->flags=DIEF_KEYID;
  271. evt->key_id=DIKI_BACKSPACE;
  272. break;

  273. caseXK_Tab:
  274. evt->flags=DIEF_KEYID;
  275. evt->key_id=DIKI_HYPER_L;
  276. break;

  277. caseXK_Return:
  278. evt->flags=DIEF_KEYID;
  279. evt->key_id=DIKI_ENTER;
  280. break;

  281. caseXK_Escape:
  282. evt->flags=DIEF_KEYID;
  283. evt->key_id=DIKI_ESCAPE;
  284. break;

  285. caseXK_Pause:
  286. evt->flags=DIEF_KEYID;
  287. evt->key_id=DIKI_PAUSE;
  288. break;

  289. /*Miscellaneousfunctionkeys*/
  290. caseXK_Help:
  291. evt->flags=DIEF_KEYSYMBOL;
  292. evt->key_symbol=DIKS_HELP;
  293. break;

  294. caseXK_Print:
  295. evt->flags=DIEF_KEYSYMBOL;
  296. evt->key_symbol=DIKS_PRINT;
  297. break;

  298. caseXK_Break:
  299. evt->flags=DIEF_KEYSYMBOL;
  300. evt->key_symbol=DIKS_BREAK;
  301. break;

  302. default:
  303. returnfalse;
  304. }

  305. returntrue;
  306. }

  307. #defineRGB16_TO_RGB32(pixel)((((pixel)&0xF800)<<8)|/
  308. (((pixel)&0x07E0)<<5)|/
  309. (((pixel)&0x001F)<<3))

  310. staticDFBResult
  311. vnc_update_screen(unsignedshort*src,intx,inty,intw,inth)
  312. {
  313. inti=0;
  314. intj=0;
  315. D_ASSERT(rfb_screen!=NULL);
  316. D_ASSERT(rfb_screen->frameBuffer!=NULL);

  317. if(g_vnc_client_nr<=0
  318. ||src==NULL
  319. ||rfb_screen==NULL
  320. ||rfb_screen->frameBuffer==NULL)
  321. {
  322. returnDFB_FALSE;
  323. }

  324. intd_bpp=4;
  325. char*dst=rfb_screen->frameBuffer;
  326. char*src_line=src;
  327. char*src_row=src;
  328. char*dst_line=dst;
  329. char*dst_row=dst;
  330. structfb_fix_screeninfo*fix=&(dfb_fbvnc->shared->fix);
  331. structfb_var_screeninfo*var=&(dfb_fbvnc->shared->current_var);
  332. ints_bpp=(var->bits_per_pixel+7)/8;

  333. if(w>var->xres_virtual
  334. ||h>var->yres_virtual)
  335. {
  336. returnDFB_FALSE;
  337. }

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

  348. src_line+=fix->line_length;
  349. dst_line=dst_row;
  350. }
  351. rfbMarkRectAsModified(rfb_screen,x,y,x+w,y+h);

  352. returnDFB_OK;
  353. }

  354. DFBResult
  355. vnc_set_video_mode(DFBDisplayLayerConfig*config)
  356. {
  357. intargc=0;
  358. char**argv=NULL;
  359. structfb_var_screeninfo*var=&(dfb_fbvnc->shared->current_var);
  360. intheight=var->yres_virtual;
  361. intwidth=var->xres_virtual;

  362. D_DEBUG("DirectFB/VNC:layerconfigproperties/n");

  363. if(rfb_screen)returnDFB_OK;

  364. rfb_screen=rfbGetScreen(&argc,argv,width,height,8,3,4);
  365. if(rfb_screen==NULL)
  366. {
  367. D_ERROR("DirectFB/VNC:Couldn'tset%dx%dx%dvideomode/n",
  368. config->width,config->height,
  369. config->pixelformat);

  370. returnDFB_FAILURE;
  371. }
  372. rfb_screen->frameBuffer=malloc(width*height*rfb_screen->depth/8);
  373. rfb_screen->kbdAddEvent=vnc_process_key_event;
  374. rfb_screen->ptrAddEvent=vnc_process_pointer_event;
  375. rfb_screen->newClientHook=vnc_client_new;
  376. rfbInitServer(rfb_screen);
  377. direct_thread_create(DTT_OUTPUT,vnc_server_thread,rfb_screen,"VNCOutput");
  378. direct_thread_create(DTT_OUTPUT,vnc_refresh_thread,rfb_screen,"VNCRefresh");
  379. returnDFB_OK;
  380. }

  381. staticvoid*
  382. vnc_server_thread(DirectThread*thread,void*data)
  383. {
  384. rfbRunEventLoop(rfb_screen,-1,FALSE);

  385. returnNULL;
  386. }

  387. staticvoid*
  388. vnc_refresh_thread(DirectThread*thread,void*data)
  389. {
  390. while(1)
  391. {
  392. if(dfb_fbvnc!=NULL&&dfb_fbvnc->framebuffer_base!=NULL&&g_vnc_client_nr>0)
  393. {
  394. vnc_update_screen(dfb_fbvnc->framebuffer_base,0,0,
  395. rfb_screen->width,rfb_screen->height);
  396. }
  397. usleep(200000);
  398. }

  399. returnNULL;
  400. }

三、 修改directfbrc,让system=fbvnc。

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



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值