FreeRDP
AdvancedKeyboardView.m
1 /*
2  Advanced keyboard view interface
3 
4  Copyright 2013 Thincast Technologies GmbH, Author: Martin Fleisz
5 
6  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7  If a copy of the MPL was not distributed with this file, You can obtain one at
8  http://mozilla.org/MPL/2.0/.
9  */
10 
11 #import "AdvancedKeyboardView.h"
12 #include <freerdp/locale/keyboard.h>
13 
14 // helper struct to define button layouts/settings
15 struct ButtonItem
16 {
17  NSString *title;
18  int tag;
19 };
20 
21 @interface AdvancedKeyboardView (Private)
22 - (UIView *)keyboardViewForItems:(struct ButtonItem *)items columns:(int)columns rows:(int)rows;
23 @end
24 
25 @implementation AdvancedKeyboardView
26 
27 @synthesize delegate = _delegate;
28 
29 // defines for the different views
30 #define KEY_SHOW_FUNCVIEW 0x1000
31 #define KEY_SHOW_CURSORVIEW 0x1001
32 #define KEY_SHOW_NUMPADVIEW 0x1002
33 #define KEY_SKIP 0x8000
34 #define KEY_MERGE_COLUMN 0x8001
35 
36 #define KEYCODE_UNICODE 0x80000000
37 
38 struct ButtonItem functionKeysItems[24] = { { @"F1", VK_F1 },
39  { @"F2", VK_F2 },
40  { @"F3", VK_F3 },
41  { @"F4", VK_F4 },
42  { @"F5", VK_F5 },
43  { @"F6", VK_F6 },
44  { @"F7", VK_F7 },
45  { @"F8", VK_F8 },
46  { @"F9", VK_F9 },
47  { @"F10", VK_F10 },
48  { @"F11", VK_F11 },
49  { @"F12", VK_F12 },
50 
51  { @"img:icon_key_arrows", KEY_SHOW_CURSORVIEW },
52  { @"Tab", VK_TAB },
53  { @"Ins", VK_INSERT | KBDEXT },
54  { @"Home", VK_HOME | KBDEXT },
55  { @"PgUp", VK_PRIOR | KBDEXT },
56  { @"img:icon_key_win", VK_LWIN | KBDEXT },
57 
58  { @"123", KEY_SHOW_NUMPADVIEW },
59  { @"Print", VK_PRINT },
60  { @"Del", VK_DELETE | KBDEXT },
61  { @"End", VK_END | KBDEXT },
62  { @"PgDn", VK_NEXT | KBDEXT },
63  { @"img:icon_key_menu", VK_APPS | KBDEXT } };
64 
65 struct ButtonItem numPadKeysItems[24] = { { @"(", KEYCODE_UNICODE | 40 },
66  { @")", KEYCODE_UNICODE | 41 },
67  { @"7", VK_NUMPAD7 },
68  { @"8", VK_NUMPAD8 },
69  { @"9", VK_NUMPAD9 },
70  { @"-", VK_SUBTRACT },
71 
72  { @"/", VK_DIVIDE | KBDEXT },
73  { @"*", VK_MULTIPLY },
74  { @"4", VK_NUMPAD4 },
75  { @"5", VK_NUMPAD5 },
76  { @"6", VK_NUMPAD6 },
77  { @"+", VK_ADD },
78 
79  { @"Fn", KEY_SHOW_FUNCVIEW },
80  { @"Num", VK_NUMLOCK },
81  { @"1", VK_NUMPAD1 },
82  { @"2", VK_NUMPAD2 },
83  { @"3", VK_NUMPAD3 },
84  { @"img:icon_key_backspace", VK_BACK },
85 
86  { @"img:icon_key_arrows", KEY_SHOW_CURSORVIEW },
87  { @"=", KEYCODE_UNICODE | 61 },
88  { @"", KEY_MERGE_COLUMN },
89  { @"0", VK_NUMPAD0 },
90  { @".", VK_DECIMAL },
91  { @"img:icon_key_return", VK_RETURN | KBDEXT } };
92 
93 struct ButtonItem cursorKeysItems[24] = { { @"", KEY_SKIP },
94  { @"", KEY_SKIP },
95  { @"", KEY_SKIP },
96  { @"", KEY_SKIP },
97  { @"", KEY_SKIP },
98  { @"", KEY_SKIP },
99 
100  { @"", KEY_SKIP },
101  { @"", KEY_SKIP },
102  { @"", KEY_SKIP },
103  { @"img:icon_key_arrow_up", VK_UP | KBDEXT },
104  { @"", KEY_SKIP },
105  { @"", KEY_SKIP },
106 
107  { @"Fn", KEY_SHOW_FUNCVIEW },
108  { @"", KEY_SKIP },
109  { @"img:icon_key_arrow_left", VK_LEFT | KBDEXT },
110  { @"", KEY_SKIP },
111  { @"img:icon_key_arrow_right", VK_RIGHT | KBDEXT },
112  { @"img:icon_key_backspace", VK_BACK },
113 
114  { @"123", KEY_SHOW_NUMPADVIEW },
115  { @"", KEY_SKIP },
116  { @"", KEY_SKIP },
117  { @"img:icon_key_arrow_down", VK_DOWN | KBDEXT },
118  { @"", KEY_SKIP },
119  { @"img:icon_key_return", VK_RETURN | KBDEXT } };
120 
121 - (void)initFunctionKeysView
122 {
123  _function_keys_view = [[self keyboardViewForItems:functionKeysItems columns:6 rows:4] retain];
124  [self addSubview:_function_keys_view];
125 }
126 
127 - (void)initNumPadKeysView
128 {
129  _numpad_keys_view = [[self keyboardViewForItems:numPadKeysItems columns:6 rows:4] retain];
130  [self addSubview:_numpad_keys_view];
131 }
132 
133 - (void)initCursorKeysView
134 {
135  _cursor_keys_view = [[self keyboardViewForItems:cursorKeysItems columns:6 rows:4] retain];
136  [self addSubview:_cursor_keys_view];
137 }
138 
139 - (id)initWithFrame:(CGRect)frame delegate:(NSObject<AdvancedKeyboardDelegate> *)delegate
140 {
141  self = [super initWithFrame:frame];
142  if (self)
143  {
144  _delegate = delegate;
145 
146  self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
147  self.backgroundColor = [UIColor blackColor];
148  // Initialization code
149 
150  [self initCursorKeysView];
151  [self initNumPadKeysView];
152  [self initFunctionKeysView];
153 
154  // set function keys view to the initial view and hide others
155  _cur_view = _function_keys_view;
156  [_numpad_keys_view setHidden:YES];
157  [_cursor_keys_view setHidden:YES];
158  }
159  return self;
160 }
161 
162 /*
163 // Only override drawRect: if you perform custom drawing.
164 // An empty implementation adversely affects performance during animation.
165 - (void)drawRect:(CGRect)rect
166 {
167  // Drawing code
168 }
169 */
170 
171 - (void)drawRect:(CGRect)rect
172 {
173  // draw a nice background gradient
174  CGContextRef currentContext = UIGraphicsGetCurrentContext();
175 
176  CGGradientRef glossGradient;
177  CGColorSpaceRef rgbColorspace;
178  size_t num_locations = 2;
179  CGFloat locations[2] = { 0.0, 1.0 };
180  CGFloat components[8] = { 1.0, 1.0, 1.0, 0.35, // Start color
181  1.0, 1.0, 1.0, 0.06 }; // End color
182 
183  rgbColorspace = CGColorSpaceCreateDeviceRGB();
184  glossGradient =
185  CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);
186 
187  CGRect currentBounds = self.bounds;
188  CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
189  CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds), currentBounds.size.height);
190  CGContextDrawLinearGradient(currentContext, glossGradient, topCenter, midCenter, 0);
191 
192  CGGradientRelease(glossGradient);
193  CGColorSpaceRelease(rgbColorspace);
194 }
195 
196 - (void)dealloc
197 {
198  [_function_keys_view autorelease];
199  [_numpad_keys_view autorelease];
200  [_cursor_keys_view autorelease];
201  [super dealloc];
202 }
203 
204 #pragma mark -
205 #pragma mark button events
206 
207 - (IBAction)keyPressed:(id)sender
208 {
209  UIButton *btn = (UIButton *)sender;
210  switch ([btn tag])
211  {
212  case KEY_SHOW_CURSORVIEW:
213  // switch to cursor view
214  [_cur_view setHidden:YES];
215  [_cursor_keys_view setHidden:NO];
216  _cur_view = _cursor_keys_view;
217  break;
218 
219  case KEY_SHOW_NUMPADVIEW:
220  // switch to numpad view
221  [_cur_view setHidden:YES];
222  [_numpad_keys_view setHidden:NO];
223  _cur_view = _numpad_keys_view;
224  break;
225 
226  case KEY_SHOW_FUNCVIEW:
227  // switch to function keys view
228  [_cur_view setHidden:YES];
229  [_function_keys_view setHidden:NO];
230  _cur_view = _function_keys_view;
231  break;
232 
233  default:
234  if ([btn tag] & KEYCODE_UNICODE)
235  {
236  if ([[self delegate] respondsToSelector:@selector(advancedKeyPressedUnicode:)])
237  [[self delegate] advancedKeyPressedUnicode:([btn tag] & ~KEYCODE_UNICODE)];
238  }
239  else
240  {
241  if ([[self delegate] respondsToSelector:@selector(advancedKeyPressedVKey:)])
242  [[self delegate] advancedKeyPressedVKey:[btn tag]];
243  }
244  break;
245  }
246 }
247 
248 @end
249 
250 #pragma mark -
251 @implementation AdvancedKeyboardView (Private)
252 
253 - (UIView *)keyboardViewForItems:(struct ButtonItem *)items columns:(int)columns rows:(int)rows
254 {
255  UIView *result_view = [[[UIView alloc] initWithFrame:self.bounds] autorelease];
256  result_view.autoresizingMask =
257  UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
258 
259  // calculate maximum button size
260  int max_btn_width = result_view.bounds.size.width / ((columns * 2) + 1);
261  int max_btn_height = result_view.bounds.size.height / ((rows * 2) + 1);
262 
263  // ensure minimum button size
264  CGSize btn_size = CGSizeMake(45, 30);
265  if (btn_size.width < max_btn_width)
266  btn_size.width = max_btn_width;
267  if (btn_size.height < max_btn_height)
268  btn_size.height = max_btn_height;
269 
270  // calc distance width and height between buttons
271  int dist_width = (result_view.bounds.size.width - (columns * btn_size.width)) / (columns + 1);
272  int dist_height = (result_view.bounds.size.height - (rows * btn_size.height)) / (rows + 1);
273 
274  UIImage *btn_background_img = [UIImage
275  imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"keyboard_button_background"
276  ofType:@"png"]];
277  for (int j = 0; j < rows; j++)
278  {
279  for (int i = 0; i < columns; i++)
280  {
281  struct ButtonItem *curItem = &items[j * columns + i];
282 
283  // skip this spot?
284  if (curItem->tag == KEY_SKIP)
285  continue;
286 
287  // create button, set autoresizing mask and add action handler
288  UIButton *btn = [UIButton buttonWithType:UIButtonTypeRoundedRect];
289  [btn setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin |
290  UIViewAutoresizingFlexibleRightMargin |
291  UIViewAutoresizingFlexibleTopMargin |
292  UIViewAutoresizingFlexibleBottomMargin |
293  UIViewAutoresizingFlexibleWidth |
294  UIViewAutoresizingFlexibleHeight)];
295  [btn addTarget:self
296  action:@selector(keyPressed:)
297  forControlEvents:UIControlEventTouchUpInside];
298 
299  // if merge is specified we merge this button's position with the next one
300  if (curItem->tag == KEY_MERGE_COLUMN)
301  {
302  // calc merged frame
303  [btn setFrame:CGRectMake(dist_width + (i * dist_width) + (i * btn_size.width),
304  dist_height + (j * dist_height) + (j * btn_size.height),
305  btn_size.width * 2 + dist_width, btn_size.height)];
306 
307  // proceed to the next column item
308  i++;
309  curItem = &items[j * columns + i];
310  }
311  else
312  {
313  [btn setFrame:CGRectMake(dist_width + (i * dist_width) + (i * btn_size.width),
314  dist_height + (j * dist_height) + (j * btn_size.height),
315  btn_size.width, btn_size.height)];
316  }
317 
318  // set button text or image parameters
319  if ([curItem->title hasPrefix:@"img:"] == YES)
320  {
321  UIImage *btn_image =
322  [UIImage imageWithContentsOfFile:[[NSBundle mainBundle]
323  pathForResource:[curItem->title
324  substringFromIndex:4]
325  ofType:@"png"]];
326  [btn setImage:btn_image forState:UIControlStateNormal];
327  }
328  else
329  {
330  [btn setTitle:curItem->title forState:UIControlStateNormal];
331  [btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
332  }
333 
334  [btn setBackgroundImage:btn_background_img forState:UIControlStateNormal];
335  [btn setTag:curItem->tag];
336 
337  // add button to view
338  [result_view addSubview:btn];
339  }
340  }
341 
342  return result_view;
343 }
344 
345 @end