1 /** EMULib Emulation Library *********************************/
2 /**                                                         **/
3 /**                          Touch.c                        **/
4 /**                                                         **/
5 /** This file contains functions that simulate joystick and **/
6 /** dialpad with the touch screen. It is normally used from **/
7 /** the platform-dependent functions that know where to get **/
8 /** pen coordinates from and where to draw pen cues to.     **/
9 /**                                                         **/
10 /** Copyright (C) Marat Fayzullin 2008-2009                 **/
11 /**     You are not allowed to distribute this software     **/
12 /**     commercially. Please, notify me, if you make any    **/
13 /**     changes to this file.                               **/
14 /*************************************************************/
15 #if !defined(BPP32) && !defined(BPP24) && !defined(BPP16) && !defined(BPP8)
16 #include "TouchMux.h"
17 #else
18 
19 #include "EMULib.h"
20 #include "Console.h"
21 #include "Touch.h"
22 #include <string.h>
23 
24 #define CLR_NORMALF PIXEL(0,0,0)         /* Normal key foreground   */
25 #define CLR_NORMALB PIXEL(255,255,255)   /* Normal key background   */
26 #define CLR_ACTIVEF PIXEL(255,255,255)   /* Active key foreground   */
27 #define CLR_ACTIVEB PIXEL(255,64,64)     /* Active key background   */
28 
29 #ifndef DEFINE_ONCE
30 #define DEFINE_ONCE
31 
32 /* Currently selected virtual keyboard key */
33 static int KBDXPos = 0;
34 static int KBDYPos = 0;
35 
36 /* Horizontal offsets of virtual keyboard lines */
37 static const int KBDOffsets[YKEYS] = { 0,0,4,-4,8,4 };
38 
39 /* Characters printed on virtual keyboard keys */
40 static const unsigned char *KBDLines[YKEYS+1] =
41 {
42   "\33\20\21\22\23\24\25\26\27\16\17\10",
43   "1234567890-=",
44   "\11QWERTYUIOP",
45   "^ASDFGHJKL;\15",
46   "ZXCVBNM,./",
47   "[]     \\'",
48   0
49 };
50 
51 /* Characters returned from virtual keyboard */
52 static unsigned char KBDKeys[YKEYS][XKEYS] =
53 {
54   {
55     0x1B,CON_F1,CON_F2,CON_F3,CON_F4,CON_F5,
56     CON_F6,CON_F7,CON_F8,CON_INSERT,CON_DELETE,CON_BS
57   },
58   { '1','2','3','4','5','6','7','8','9','0','-','=' },
59   { CON_TAB,'Q','W','E','R','T','Y','U','I','O','P',0 },
60   { '^','A','S','D','F','G','H','J','K','L',';',CON_ENTER },
61   { 'Z','X','C','V','B','N','M',',','.','/',0,0 },
62   { '[',']',' ',' ',' ',' ',' ','\\','\'',0,0,0 }
63 };
64 
65 /** GenericPenJoystick() *************************************/
66 /** Get simulated joystick buttons from touch screen UI.    **/
67 /** Result compatible with GetJoystick().                   **/
68 /*************************************************************/
GenericPenJoystick(int X,int Y,int W,int H)69 unsigned int GenericPenJoystick(int X,int Y,int W,int H)
70 {
71   unsigned int J;
72 
73   /* Simulate joystick when pen touches the screen at X,Y */
74   J = 0;
75 
76   /* Don't accept touches outside of the window frame */
77   if((X<0)||(Y<0)||(X>=W)||(Y>=H)) return(0);
78   W/= 3;
79 
80   /* Top 1/16 of the widget: FIREL and FIRER */
81   if(Y<(H>>4))
82   { if(X<W) J|=BTN_FIREL; else if(X>=(W<<1)) J|=BTN_FIRER; }
83 
84   /* Bottom 1/16 of the widget: SELECT/EXIT and START */
85   if(!J&&(Y>=(H-(H>>4))))
86   { if(X<W) J|=BTN_SELECT|BTN_EXIT; else if(X>=(W<<1)) J|=BTN_START; }
87 
88   /* Right 1/3 of the screen is the fire buttons */
89   if(!J&&(X>=(W<<1)))
90   {
91     /* Fire buttons overlap */
92     if(Y<=(H>>1)+(H>>4)) J|=BTN_FIREB;
93     if(Y>=(H>>1)-(H>>4)) J|=BTN_FIREA;
94   }
95 
96   /* Left 1/3 of the screen is the directional pad */
97   if(!J&&(X<W))
98   {
99     H/=3;
100     W/=3;
101     if(X<W) J|=BTN_LEFT; else if(X>=(W<<1)) J|=BTN_RIGHT;
102     if(Y<H) J|=BTN_UP;   else if(Y>=(H<<1)) J|=BTN_DOWN;
103   }
104 
105   /* Done, return simulated "joystick" state */
106   return(J);
107 }
108 
109 /** GenericPenDialpad() **************************************/
110 /** Get simulated dialpad buttons from touch screen UI.     **/
111 /*************************************************************/
GenericPenDialpad(int X,int Y,int W,int H)112 unsigned char GenericPenDialpad(int X,int Y,int W,int H)
113 {
114   /* Dialpad is the middle 1/3 of the screen */
115   W /= 3;
116   return(
117     (Y>=0)&&(Y<H)&&(X>=W)&&(X<(W<<1))?
118     3*(X-W)/W+3*(Y/(H>>2)) : 0
119   );
120 }
121 
122 /** GenericPenKeyboard() *************************************/
123 /** Get virtual on-screen keyboard buttons.                 **/
124 /*************************************************************/
GenericPenKeyboard(int X,int Y,int W,int H)125 unsigned char GenericPenKeyboard(int X,int Y,int W,int H)
126 {
127   int J;
128 
129   /* Pen coordinates relative to keyboard's top left corner */
130   X -= W-KEYSTEP*XKEYS-8;
131   Y -= H-KEYSTEP*YKEYS-8;
132 
133   /* Pen must be inside the keyboard */
134   if((X<0)||(Y<0)) return(0);
135 
136   /* Keyboard row index */
137   Y/= KEYSTEP;
138   if(Y>=YKEYS) return(0);
139 
140   /* Adjust for row position on screen */
141   for(J=0;J<Y;++J) X-=KBDOffsets[J];
142   if(X<0) return(0);
143 
144   /* Keyboard column index */
145   X/= KEYSTEP;
146   if(X>=XKEYS) return(0);
147 
148   /* Memorize last pressed key */
149   KBDXPos = X;
150   KBDYPos = Y;
151 
152   /* Return key */
153   return(KBDKeys[Y][X]);
154 }
155 
156 /** GenericDialKeyboard() ************************************/
157 /** Process dialpad input to the virtual keyboard. Returns  **/
158 /** virtual keyboard key if selected, or 0 if not.          **/
159 /*************************************************************/
GenericDialKeyboard(unsigned char Key)160 unsigned char GenericDialKeyboard(unsigned char Key)
161 {
162   /* Interpret input key */
163   switch(Key)
164   {
165     case CON_LEFT:
166       KBDXPos = (KBDXPos>0? KBDXPos:strlen(KBDLines[KBDYPos]))-1;
167       break;
168     case CON_RIGHT:
169       KBDXPos = KBDXPos<strlen(KBDLines[KBDYPos])-1? KBDXPos+1:0;
170       break;
171     case CON_UP:
172       KBDYPos = KBDYPos>0? KBDYPos-1:YKEYS-1;
173       KBDXPos = KBDXPos<strlen(KBDLines[KBDYPos])? KBDXPos:strlen(KBDLines[KBDYPos])-1;
174       break;
175     case CON_DOWN:
176       KBDYPos = KBDYPos<YKEYS-1? KBDYPos+1:0;
177       KBDXPos = KBDXPos<strlen(KBDLines[KBDYPos])? KBDXPos:strlen(KBDLines[KBDYPos])-1;
178       break;
179     case CON_OK:
180       /* Return ASCII character */
181       return(KBDLines[KBDYPos][KBDXPos]);
182   }
183 
184   /* Key has not been interpreted */
185   return(0);
186 }
187 
188 #endif /* DEFINE_ONCE */
189 
190 /** DrawVLine()/DrawHLine() **********************************/
191 /** Draw dotted lines used to show cues for PenJoystick().  **/
192 /*************************************************************/
DrawVLine(Image * Img,int X,int Y1,int Y2,pixel Color)193 static void DrawVLine(Image *Img,int X,int Y1,int Y2,pixel Color)
194 {
195   pixel *P;
196   int J;
197 
198   if(Y1>Y2) { J=Y1;Y1=Y2;Y2=J; }
199   P = (pixel *)Img->Data+Img->L*Y1+X;
200   for(J=Y1;J<=Y2;J+=4) { *P=Color;P+=Img->L<<2; }
201 }
202 
DrawHLine(Image * Img,int X1,int X2,int Y,pixel Color)203 static void DrawHLine(Image *Img,int X1,int X2,int Y,pixel Color)
204 {
205   pixel *P;
206   int J;
207 
208   if(X1>X2) { J=X1;X1=X2;X2=J; }
209   P = (pixel *)Img->Data+Img->L*Y+X1;
210   for(J=X1;J<=X2;J+=4) { *P=Color;P+=4; }
211 }
212 
213 /** DrawPenCues() ********************************************/
214 /** Overlay dotted cue lines for using PenJoystick() onto a **/
215 /** given image. Show dialpad cues if requested.            **/
216 /*************************************************************/
DrawPenCues(Image * Img,int ShowDialpad,pixel Color)217 void DrawPenCues(Image *Img,int ShowDialpad,pixel Color)
218 {
219   pixel *P;
220   int W,H,W9,W3,H3;
221 
222   P  = (pixel *)Img->Data;
223   W  = Img->W;
224   H  = Img->H;
225   W9 = W/9;
226   W3 = W/3;
227   H3 = H/3;
228 
229   /* Vertical edges */
230   DrawVLine(Img,W3,0,H-1,Color);
231   DrawVLine(Img,W-W3,0,H-1,Color);
232 
233   /* Corner buttons */
234   DrawHLine(Img,0,W3,H>>4,Color);
235   DrawHLine(Img,W-W3,W-1,H>>4,Color);
236   DrawHLine(Img,0,W3,H-(H>>4),Color);
237   DrawHLine(Img,W-W3,W-1,H-(H>>4),Color);
238 
239   /* Fire buttons (with overlap) */
240   DrawHLine(Img,W-W3,W-1,(H>>1)-(H>>4),Color);
241   DrawHLine(Img,W-W3,W-1,(H>>1)+(H>>4),Color);
242 
243   /* Directional buttons */
244   DrawVLine(Img,W9,H>>4,H-(H>>4),Color);
245   DrawVLine(Img,W3-W9,H>>4,H-(H>>4),Color);
246   DrawHLine(Img,0,W3,H3,Color);
247   DrawHLine(Img,0,W3,H-H3,Color);
248 
249   /* Button labels */
250   PrintXY(Img,"L",2,2,Color,-1);
251   PrintXY(Img,"R",W-W3+2,2,Color,-1);
252   PrintXY(Img,"B",W-W3+2,(H>>4)+2,Color,-1);
253   PrintXY(Img,"A+B",W-W3+2,(H>>1)-(H>>4)+2,Color,-1);
254   PrintXY(Img,"A",W-W3+2,(H>>1)+(H>>4)+2,Color,-1);
255   PrintXY(Img,"SELECT",2,H-(H>>4)+2,Color,-1);
256   PrintXY(Img,"START",W-W3+2,H-(H>>4)+2,Color,-1);
257 
258   /* If requested, show on-screen dialpad */
259   if(ShowDialpad)
260   {
261     DrawHLine(Img,W3,W-W3,H>>2,Color);
262     DrawHLine(Img,W3,W-W3,H>>1,Color);
263     DrawHLine(Img,W3,W-W3,H-(H>>2),Color);
264     DrawVLine(Img,W3+W9,0,H-1,Color);
265     DrawVLine(Img,W-W3-W9,0,H-1,Color);
266     PrintXY(Img,"1",W3+2,2,Color,-1);
267     PrintXY(Img,"2",W3+W9+2,2,Color,-1);
268     PrintXY(Img,"3",W-W3-W9+2,2,Color,-1);
269     PrintXY(Img,"4",W3+2,(H>>2)+2,Color,-1);
270     PrintXY(Img,"5",W3+W9+2,(H>>2)+2,Color,-1);
271     PrintXY(Img,"6",W-W3-W9+2,(H>>2)+2,Color,-1);
272     PrintXY(Img,"7",W3+2,(H>>1)+2,Color,-1);
273     PrintXY(Img,"8",W3+W9+2,(H>>1)+2,Color,-1);
274     PrintXY(Img,"9",W-W3-W9+2,(H>>1)+2,Color,-1);
275     PrintXY(Img,"*",W3+2,H-(H>>2)+2,Color,-1);
276     PrintXY(Img,"0",W3+W9+2,H-(H>>2)+2,Color,-1);
277     PrintXY(Img,"#",W-W3-W9+2,H-(H>>2)+2,Color,-1);
278   }
279 }
280 
281 /** DrawKeyboard() *******************************************/
282 /** Draw virtual keyboard in a given image. Key modifiers   **/
283 /** and the key code passed in CurKey are highlighted.      **/
284 /*************************************************************/
DrawKeyboard(Image * Img,unsigned int CurKey)285 void DrawKeyboard(Image *Img,unsigned int CurKey)
286 {
287   unsigned int X,Y,J,I,K,L;
288   char S[2];
289   pixel *P;
290 
291   /* Keyboard in the right-bottom corner by default */
292   X=Img->W-KEYSTEP*XKEYS-8;
293   Y=Img->H-KEYSTEP*YKEYS-8;
294 
295   /* Draw modifiers */
296   if(CurKey&CON_MODES)
297   {
298     J=X;
299     if(CurKey&CON_SHIFT)   { PrintXY(Img,"SHIFT",J,Y-8,CLR_ACTIVEB,-1);J+=48; }
300     if(CurKey&CON_CONTROL) { PrintXY(Img,"CTRL",J,Y-8,CLR_ACTIVEB,-1);J+=40; }
301     if(CurKey&CON_ALT)     { PrintXY(Img,"ALT",J,Y-8,CLR_ACTIVEB,-1);J+=32; }
302   }
303 
304   /* Draw keys */
305   for(I=J=0,S[1]='\0';KBDLines[I];++I,Y+=KEYSTEP,X+=KBDOffsets[I]-J*KEYSTEP)
306     for(J=0;KBDLines[I][J];++J,X+=KEYSTEP)
307     {
308       /* Draw key frame */
309       P = (pixel *)Img->Data
310         + Img->L*(Y+(KEYSTEP-KEYSIZE)/2)
311         + X+(KEYSTEP-KEYSIZE)/2;
312 
313       /* Highlight current key */
314       if(KBDKeys[I][J]==(CurKey&CON_KEYCODE))
315       {
316         for(K=1;K<KEYSIZE-1;++K) P[K]=CLR_ACTIVEB;
317         for(K=1,P+=Img->L;K<KEYSIZE-1;++K,P+=Img->L)
318           for(L=0;L<KEYSIZE;++L) P[L]=CLR_ACTIVEB;
319         for(K=1;K<KEYSIZE-1;++K) P[K]=CLR_ACTIVEB;
320         K=CLR_ACTIVEF;
321       }
322       else
323       {
324         for(K=1;K<KEYSIZE-1;++K) P[K]=CLR_NORMALF;
325         for(K=1,P+=Img->L;K<KEYSIZE-1;++K,P+=Img->L)
326         {
327           for(L=1;L<KEYSIZE-1;++L) P[L]=CLR_NORMALB;
328           P[0]=P[KEYSIZE-1]=CLR_NORMALF;
329         }
330         for(K=1;K<KEYSIZE-1;++K) P[K]=CLR_NORMALF;
331         K=CLR_NORMALF;
332       }
333 
334       /* Draw key label */
335       S[0]=KBDLines[I][J];
336       PrintXY(Img,S,X+(KEYSTEP-8)/2,Y+(KEYSTEP-8)/2,K,-1);
337     }
338 }
339 
340 #undef CLR_NORMALF
341 #undef CLR_NORMALB
342 #undef CLR_ACTIVEF
343 #undef CLR_ACTIVEB
344 
345 #endif /* BPP32||BPP24||BPP16||BPP8 */
346