FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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
15struct 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
38struct 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
65struct 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
93struct 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