xref: /haiku/src/add-ons/input_server/devices/keyboard/KeyboardInputDevice.cpp (revision 93a78ecaa45114d68952d08c4778f073515102f2)
1 /*
2  * Copyright 2004-2006, Jérôme Duval. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "KeyboardInputDevice.h"
8 #include "kb_mouse_driver.h"
9 
10 #include <Application.h>
11 #include <Directory.h>
12 #include <Entry.h>
13 #include <NodeMonitor.h>
14 #include <Path.h>
15 #include <String.h>
16 
17 #include <errno.h>
18 #include <new>
19 #include <stdlib.h>
20 #include <unistd.h>
21 
22 
23 #if DEBUG
24 FILE *KeyboardInputDevice::sLogFile = NULL;
25 #endif
26 
27 const static uint32 kKeyboardThreadPriority = B_FIRST_REAL_TIME_PRIORITY + 4;
28 const static char *kKeyboardDevicesDirectory = "/dev/input/keyboard";
29 
30 // "/dev/" is automatically prepended by StartMonitoringDevice()
31 const static char *kKeyboardDevicesDirectoryPS2 = "input/keyboard/at";
32 const static char *kKeyboardDevicesDirectoryUSB = "input/keyboard/usb";
33 
34 const static uint32 kATKeycodeMap[] = {
35 	0x1,	// Esc
36 	0x12, 	// 1
37 	0x13,	// 2
38 	0x14,	// 3
39 	0x15,	// 4
40 	0x16,	// 5
41 	0x17,	// 6
42 	0x18,	// 7
43 	0x19,	// 8
44 	0x1a,	// 9
45 	0x1b,	// 0
46 	0x1c,	// -
47 	0x1d,	// =
48 	0x1e,	// BACKSPACE
49 	0x26,	// TAB
50 	0x27,	// Q
51 	0x28,	// W
52 	0x29,	// E
53 	0x2a,	// R
54 	0x2b,	// T
55 	0x2c,	// Y
56 	0x2d,	// U
57 	0x2e,	// I
58 	0x2f,	// O
59 	0x30,	// P
60 	0x31,   // [
61 	0x32,	// ]
62 	0x47,	// ENTER
63 	0x5c,	// Left Control
64 	0x3c,	// A
65 	0x3d,	// S
66 	0x3e,	// D
67 	0x3f,	// F
68 	0x40,	// G
69 	0x41,	// H
70 	0x42,	// J
71 	0x43,	// K
72 	0x44,	// L
73 	0x45,	// ;
74 	0x46,	// '
75 	0x11,	// `
76 	0x4b,	// Left Shift
77 	0x33, 	// \ (backslash -- note: don't remove non-white-space after BS char)
78 	0x4c,	// Z
79 	0x4d,	// X
80 	0x4e,	// C
81 	0x4f,	// V
82 	0x50,	// B
83 	0x51,	// N
84 	0x52,	// M
85 	0x53,	// ,
86 	0x54,	// .
87 	0x55,	// /
88 	0x56,	// Right Shift
89 	0x24,	// *
90 	0x5d,	// Left Alt
91 	0x5e,	// Space
92 	0x3b,	// Caps
93 	0x02,	// F1
94 	0x03,	// F2
95 	0x04,	// F3
96 	0x05,	// F4
97 	0x06,	// F5
98 	0x07,	// F6
99 	0x08,	// F7
100 	0x09,	// F8
101 	0x0a,	// F9
102 	0x0b,	// F10
103 	0x22,	// Num
104 	0x0f,	// Scroll
105 	0x37,	// KP 7
106 	0x38,	// KP 8
107 	0x39,	// KP 9
108 	0x25,	// KP -
109 	0x48,	// KP 4
110 	0x49,	// KP 5
111 	0x4a,	// KP 6
112 	0x3a,	// KP +
113 	0x58,	// KP 1
114 	0x59,	// KP 2
115 	0x5a,	// KP 3
116 	0x64,	// KP 0
117 	0x65,	// KP .
118 	0x00,	// UNMAPPED
119 	0x00,	// UNMAPPED
120 	0x69,	// <
121 	0x0c,	// F11
122 	0x0d,	// F12
123 	0x00,   // UNMAPPED
124 	0x00,   // UNMAPPED		90
125 	0x00,   // UNMAPPED
126 	0x00,   // UNMAPPED
127 	0x00,   // UNMAPPED
128 	0x00,   // UNMAPPED
129 	0x00,   // UNMAPPED
130 	0x00,   // UNMAPPED
131 	0x00,   // UNMAPPED
132 	0x00,   // UNMAPPED
133 	0x00,   // UNMAPPED
134 	0x00,   // UNMAPPED		100
135 	0x00,   // UNMAPPED
136 	0x00,   // UNMAPPED
137 	0x00,   // UNMAPPED
138 	0x00,   // UNMAPPED
139 	0x00,   // UNMAPPED
140 	0x00,   // UNMAPPED
141 	0x00,   // UNMAPPED
142 	0x00,   // UNMAPPED
143 	0x00,   // UNMAPPED
144 	0x00,   // UNMAPPED		110
145 	0x00,   // UNMAPPED
146 	0x6e,   // Katakana/Hiragana, second key right to spacebar, japanese
147 	0x00,   // UNMAPPED
148 	0x00,   // UNMAPPED
149 	0x6b,   // Ro (\\ key, japanese)
150 	0x00,   // UNMAPPED
151 	0x00,   // UNMAPPED
152 	0x00,   // UNMAPPED
153 	0x00,   // UNMAPPED
154 	0x00,   // UNMAPPED		120
155 	0x6d,   // Henkan, first key right to spacebar, japanese
156 	0x00,   // UNMAPPED
157 	0x6c,   // Muhenkan, key left to spacebar, japanese
158 	0x00,   // UNMAPPED
159 	0x6a,   // Yen (macron key, japanese)
160 	0x70,   // Keypad . on Brazilian ABNT2
161 	0x00,   // UNMAPPED
162 	0x00,   // UNMAPPED
163 	0x00,   // UNMAPPED
164 	0x00,   // UNMAPPED		130
165 	0x00,   // UNMAPPED
166 	0x00,   // UNMAPPED
167 	0x00,   // UNMAPPED
168 	0x00,   // UNMAPPED
169 	0x00,   // UNMAPPED
170 	0x00,   // UNMAPPED
171 	0x00,   // UNMAPPED
172 	0x00,   // UNMAPPED
173 	0x00,   // UNMAPPED
174 	0x00,   // UNMAPPED		140
175 	0x00,   // UNMAPPED
176 	0x00,   // UNMAPPED
177 	0x00,   // UNMAPPED
178 	0x00,   // UNMAPPED
179 	0x00,   // UNMAPPED
180 	0x00,   // UNMAPPED
181 	0x00,   // UNMAPPED
182 	0x00,   // UNMAPPED
183 	0x00,   // UNMAPPED
184 	0x00,   // UNMAPPED		150
185 	0x00,   // UNMAPPED
186 	0x00,   // UNMAPPED
187 	0x00,   // UNMAPPED
188 	0x00,   // UNMAPPED
189 	0x00,   // UNMAPPED
190 	0x5b,   // KP Enter
191 	0x60,   // Right Control
192 	0x00,   // UNMAPPED
193 	0x00,   // UNMAPPED
194 	0x00,   // UNMAPPED		160
195 	0x00,   // UNMAPPED
196 	0x00,   // UNMAPPED
197 	0x00,   // UNMAPPED
198 	0x00,   // UNMAPPED
199 	0x00,   // UNMAPPED
200 	0x00,   // UNMAPPED
201 	0x00,   // UNMAPPED
202 	0x00,   // UNMAPPED
203 	0x00,   // UNMAPPED
204 	0x00,   // UNMAPPED		170
205 	0x00,   // UNMAPPED
206 	0x00,   // UNMAPPED
207 	0x00,   // UNMAPPED
208 	0x00,   // UNMAPPED
209 	0x00,   // UNMAPPED
210 	0x00,   // UNMAPPED
211 	0x00,   // UNMAPPED
212 	0x00,   // UNMAPPED
213 	0x00,   // UNMAPPED
214 	0x00,   // UNMAPPED		180
215 	0x23,   // KP /
216 	0x00,   // UNMAPPED
217 	0x0e,   // Print Screen
218 	0x5f,   // Right Alt
219 	0x00,   // UNMAPPED
220 	0x00,   // UNMAPPED
221 	0x00,   // UNMAPPED
222 	0x00,   // UNMAPPED
223 	0x00,   // UNMAPPED
224 	0x00,   // UNMAPPED		190
225 	0x00,   // UNMAPPED
226 	0x00,   // UNMAPPED
227 	0x00,   // UNMAPPED
228 	0x00,   // UNMAPPED
229 	0x00,   // UNMAPPED
230 	0x00,   // UNMAPPED
231 	0x00,   // UNMAPPED
232 	0x7f,   // Break
233 	0x20,   // Home
234 	0x57,	// Up Arrow		200
235 	0x21,   // Page Up
236 	0x00,   // UNMAPPED
237 	0x61,   // Left Arrow
238 	0x00,   // UNMAPPED
239 	0x63,   // Right Arrow
240 	0x00,   // UNMAPPED
241 	0x35,   // End
242 	0x62,   // Down Arrow
243 	0x36,   // Page Down
244 	0x1f,   // Insert		200
245 	0x34,   // Delete
246 	0x00,   // UNMAPPED
247 	0x00,   // UNMAPPED
248 	0x00,   // UNMAPPED
249 	0x00,   // UNMAPPED
250 	0x00,   // UNMAPPED
251 	0x00,   // UNMAPPED
252 	0x00,   // UNMAPPED
253 	0x66,   // Left Gui
254 	0x67,   // Right Gui	210
255 	0x68,   // Menu
256 	0x00,   // UNMAPPED
257 	0x00,   // UNMAPPED
258 	0x00,   // UNMAPPED
259 	0x00,   // UNMAPPED
260 	0x00,   // UNMAPPED
261 	0x00,   // UNMAPPED
262 	0x00,   // UNMAPPED
263 	0x00,   // UNMAPPED
264 	0x00,   // UNMAPPED		220
265 	0x00,   // UNMAPPED
266 	0x00,   // UNMAPPED
267 	0x00,   // UNMAPPED
268 	0x00,   // UNMAPPED
269 	0x00,   // UNMAPPED
270 	0x00,   // UNMAPPED
271 	0x00,   // UNMAPPED
272 	0x00,   // UNMAPPED
273 	0x00,   // UNMAPPED
274 	0x00,   // UNMAPPED
275 	0x00,   // UNMAPPED
276 	0x00,   // UNMAPPED
277 	0x00,   // UNMAPPED
278 	0x00,   // UNMAPPED
279 	0x00,   // UNMAPPED
280 	0x00,   // UNMAPPED
281 	0x00,   // UNMAPPED
282 	0x00,   // UNMAPPED
283 	0x00,   // UNMAPPED
284 	0x00,   // UNMAPPED
285 	0x00,   // UNMAPPED
286 	0x00,   // UNMAPPED
287 	0x00,   // UNMAPPED
288 	0x00,   // UNMAPPED
289 	0x00,   // UNMAPPED
290 	0x00,   // UNMAPPED
291 	0x00,   // UNMAPPED
292 	0x00,   // UNMAPPED
293 	0x00,   // UNMAPPED
294 	0x00,   // UNMAPPED
295 	0x00,   // UNMAPPED
296 	0x00,   // UNMAPPED
297 	0x00,   // UNMAPPED
298 	0x00,   // UNMAPPED
299 	0x00,   // UNMAPPED
300 	0x00,   // UNMAPPED
301 	0x00,   // UNMAPPED
302 	0x00,   // UNMAPPED
303 	0x00,   // UNMAPPED
304 	0x00,   // UNMAPPED
305 	0x00,   // UNMAPPED
306 	0x00,   // UNMAPPED
307 	0x00,   // UNMAPPED
308 	0x00,   // UNMAPPED
309 	0x00,   // UNMAPPED
310 	0x00,   // UNMAPPED
311 	0x00,   // UNMAPPED
312 	0x00,   // UNMAPPED
313 	0x00,   // UNMAPPED
314 	0x00,   // UNMAPPED
315 	0x00,   // UNMAPPED
316 	0x00,   // UNMAPPED
317 	0x00,   // UNMAPPED
318 	0x00,   // UNMAPPED
319 	0x00,   // UNMAPPED
320 	0x00,   // UNMAPPED
321 	0x00,   // UNMAPPED
322 	0x00,   // UNMAPPED
323 	0x00,   // UNMAPPED
324 	0x00,   // UNMAPPED
325 
326 };
327 
328 
329 extern "C"
330 BInputServerDevice *
331 instantiate_input_device()
332 {
333 	return new (std::nothrow) KeyboardInputDevice();
334 }
335 
336 
337 static char *
338 get_short_name(const char *longName)
339 {
340 	CALLED();
341 	BString string(longName);
342 	BString name;
343 
344 	int32 slash = string.FindLast("/");
345 	string.CopyInto(name, slash + 1, string.Length() - slash);
346 	int32 index = atoi(name.String()) + 1;
347 
348 	int32 previousSlash = string.FindLast("/", slash);
349 	string.CopyInto(name, previousSlash + 1, slash - previousSlash - 1);
350 
351 	// some special handling so that we get "USB" and "AT" instead of "usb"/"at"
352 	if (name.Length() < 4)
353 		name.ToUpper();
354 	else
355 		name.Capitalize();
356 
357 	name << " Keyboard " << index;
358 
359 	return strdup(name.String());
360 }
361 
362 
363 //	#pragma mark -
364 
365 
366 KeyboardInputDevice::KeyboardInputDevice()
367 	:
368 	fTMWindow(NULL)
369 {
370 #if DEBUG
371 	if (sLogFile == NULL)
372 		sLogFile = fopen("/var/log/keyboard_device_log.log", "a");
373 #endif
374 	CALLED();
375 }
376 
377 
378 KeyboardInputDevice::~KeyboardInputDevice()
379 {
380 	CALLED();
381 	StopMonitoringDevice(kKeyboardDevicesDirectoryUSB);
382 	StopMonitoringDevice(kKeyboardDevicesDirectoryPS2);
383 
384 	int count = fDevices.CountItems();
385 	while (count-- > 0) {
386 		delete (keyboard_device *)fDevices.RemoveItem((int32)0);
387 	}
388 
389 #if DEBUG
390 	fclose(sLogFile);
391 #endif
392 }
393 
394 
395 status_t
396 KeyboardInputDevice::SystemShuttingDown()
397 {
398 	CALLED();
399 	if (fTMWindow)
400 		fTMWindow->PostMessage(SYSTEM_SHUTTING_DOWN);
401 
402 	return B_OK;
403 }
404 
405 
406 status_t
407 KeyboardInputDevice::_InitFromSettings(void *cookie, uint32 opcode)
408 {
409 	CALLED();
410 
411 	keyboard_device *device = (keyboard_device *)cookie;
412 
413 	if (opcode == 0 || opcode == B_KEY_REPEAT_RATE_CHANGED) {
414 		if (get_key_repeat_rate(&device->settings.key_repeat_rate) != B_OK)
415 			LOG_ERR("error when get_key_repeat_rate\n");
416 		else if (ioctl(device->fd, KB_SET_KEY_REPEAT_RATE,
417 				&device->settings.key_repeat_rate) != B_OK)
418 			LOG_ERR("error when KB_SET_KEY_REPEAT_RATE, fd:%d\n", device->fd);
419 	}
420 
421 	if (opcode == 0 || opcode == B_KEY_REPEAT_DELAY_CHANGED) {
422 		if (get_key_repeat_delay(&device->settings.key_repeat_delay) != B_OK)
423 			LOG_ERR("error when get_key_repeat_delay\n");
424 		else if (ioctl(device->fd, KB_SET_KEY_REPEAT_DELAY,
425 				&device->settings.key_repeat_delay) != B_OK)
426 			LOG_ERR("error when KB_SET_KEY_REPEAT_DELAY, fd:%d\n", device->fd);
427 	}
428 
429 	if (opcode == 0
430 		|| opcode == B_KEY_MAP_CHANGED
431 		|| opcode == B_KEY_LOCKS_CHANGED) {
432 		fKeymap.LoadCurrent();
433 		device->modifiers = fKeymap.Locks();
434 		_SetLeds(device);
435 	}
436 
437 	return B_OK;
438 }
439 
440 
441 status_t
442 KeyboardInputDevice::InitCheck()
443 {
444 	CALLED();
445 	// TODO: this doesn't belong here!
446 	_RecursiveScan(kKeyboardDevicesDirectory);
447 
448 	StartMonitoringDevice(kKeyboardDevicesDirectoryPS2);
449 	StartMonitoringDevice(kKeyboardDevicesDirectoryUSB);
450 
451 	return B_OK;
452 }
453 
454 
455 status_t
456 KeyboardInputDevice::Start(const char *name, void *cookie)
457 {
458 	CALLED();
459 	keyboard_device *device = (keyboard_device *)cookie;
460 
461 	if ((device->fd = open(device->path, O_RDWR)) < B_OK) {
462 		fprintf(stderr, "error when opening %s: %s\n", device->path, strerror(errno));
463 		return B_ERROR;
464 	}
465 
466 	_InitFromSettings(device);
467 
468 	char threadName[B_OS_NAME_LENGTH];
469 	snprintf(threadName, B_OS_NAME_LENGTH, "%s watcher", name);
470 
471 	device->active = true;
472 	device->device_watcher = spawn_thread(_DeviceWatcher, threadName,
473 		kKeyboardThreadPriority, device);
474 	if (device->device_watcher < B_OK)
475 		return device->device_watcher;
476 
477 	resume_thread(device->device_watcher);
478 	return B_OK;
479 }
480 
481 
482 status_t
483 KeyboardInputDevice::Stop(const char *name, void *cookie)
484 {
485 	CALLED();
486 	keyboard_device *device = (keyboard_device *)cookie;
487 
488 	LOG("Stop(%s)\n", name);
489 
490 	close(device->fd);
491 	device->fd = -1;
492 
493 	device->active = false;
494 	if (device->device_watcher >= 0) {
495 		suspend_thread(device->device_watcher);
496 		resume_thread(device->device_watcher);
497 		status_t dummy;
498 		wait_for_thread(device->device_watcher, &dummy);
499 	}
500 
501 	if (fTMWindow) {
502 		fTMWindow->PostMessage(B_QUIT_REQUESTED);
503 		fTMWindow = NULL;
504 	}
505 
506 	return B_OK;
507 }
508 
509 
510 status_t
511 KeyboardInputDevice::Control(const char *name, void *cookie,
512 	uint32 command, BMessage *message)
513 {
514 	CALLED();
515 	LOG("Control(%s, code: %lu)\n", name, command);
516 
517 	if (command == B_NODE_MONITOR)
518 		_HandleMonitor(message);
519 	else if (command >= B_KEY_MAP_CHANGED
520 		&& command <= B_KEY_REPEAT_RATE_CHANGED) {
521 		_InitFromSettings(cookie, command);
522 	}
523 	return B_OK;
524 }
525 
526 
527 status_t
528 KeyboardInputDevice::_HandleMonitor(BMessage *message)
529 {
530 	CALLED();
531 	int32 opcode = 0;
532 	status_t status;
533 	if ((status = message->FindInt32("opcode", &opcode)) < B_OK)
534 		return status;
535 
536 	if (opcode != B_ENTRY_CREATED
537 		&& opcode != B_ENTRY_REMOVED)
538 		return B_OK;
539 
540 	BEntry entry;
541 	BPath path;
542 	dev_t device;
543 	ino_t directory;
544 	const char *name = NULL;
545 
546 	message->FindInt32("device", &device);
547 	message->FindInt64("directory", &directory);
548 	message->FindString("name", &name);
549 
550 	entry_ref ref(device, directory, name);
551 
552 	if ((status = entry.SetTo(&ref)) != B_OK)
553 		return status;
554 	if ((status = entry.GetPath(&path)) != B_OK)
555 		return status;
556 	if ((status = path.InitCheck()) != B_OK)
557 		return status;
558 
559 	if (opcode == B_ENTRY_CREATED)
560 		_AddDevice(path.Path());
561 	else
562 		_RemoveDevice(path.Path());
563 
564 	return status;
565 }
566 
567 
568 status_t
569 KeyboardInputDevice::_AddDevice(const char *path)
570 {
571 	CALLED();
572 	keyboard_device *device = new (std::nothrow) keyboard_device(path);
573 	if (device == NULL)
574 		return B_NO_MEMORY;
575 
576 	device->owner = this;
577 
578 	input_device_ref *devices[2];
579 	devices[0] = &device->device_ref;
580 	devices[1] = NULL;
581 
582 	fDevices.AddItem(device);
583 
584 	return RegisterDevices(devices);
585 }
586 
587 
588 status_t
589 KeyboardInputDevice::_RemoveDevice(const char *path)
590 {
591 	CALLED();
592 	keyboard_device *device;
593 	for (int i = 0; (device = (keyboard_device *)fDevices.ItemAt(i)) != NULL; i++) {
594 		if (!strcmp(device->path, path)) {
595 			fDevices.RemoveItem(device);
596 
597 			input_device_ref *devices[2];
598 			devices[0] = &device->device_ref;
599 			devices[1] = NULL;
600 			UnregisterDevices(devices);
601 
602 			delete device;
603 			return B_OK;
604 		}
605 	}
606 
607 	return B_ENTRY_NOT_FOUND;
608 }
609 
610 
611 /*static*/ int32
612 KeyboardInputDevice::_DeviceWatcher(void *arg)
613 {
614 	CALLED();
615 	keyboard_device* device = (keyboard_device *)arg;
616 	KeyboardInputDevice* owner = device->owner;
617 	uint8 buffer[16];
618 	uint8 activeDeadKey = 0;
619 	Keymap* keymap = &owner->fKeymap;
620 	uint32 lastKeyCode = 0;
621 	uint32 repeatCount = 1;
622 	uint8 states[16];
623 
624 	memset(states, 0, sizeof(states));
625 
626 	LOG("%s\n", __PRETTY_FUNCTION__);
627 
628 	while (device->active) {
629 		if (ioctl(device->fd, KB_READ, &buffer) != B_OK)
630 			return 0;
631 
632 		uint32 keycode = 0;
633 		bool isKeyDown = false;
634 		bigtime_t timestamp = 0;
635 
636 		LOG("KB_READ :");
637 
638 		if (device->isAT) {
639 			at_kbd_io *at_kbd = (at_kbd_io *)buffer;
640 			if (at_kbd->scancode > 0)
641 				keycode = kATKeycodeMap[at_kbd->scancode-1];
642 			isKeyDown = at_kbd->is_keydown;
643 			timestamp = at_kbd->timestamp;
644 			LOG(" %02x", at_kbd->scancode);
645 		} else {
646 			raw_key_info *raw_kbd = (raw_key_info *)buffer;
647 			isKeyDown = raw_kbd->is_keydown;
648 			timestamp = raw_kbd->timestamp;
649 			keycode = raw_kbd->be_keycode;
650 		}
651 
652 		if (keycode == 0)
653 			continue;
654 
655 		LOG(" %Ld, %02x, %02lx\n", timestamp, isKeyDown, keycode);
656 
657 		if (isKeyDown && keycode == 0x68) {
658 			// MENU KEY for OpenTracker 5.2.0+
659 			bool noOtherKeyPressed = true;
660 			for (int32 i = 0; i < 16; i++) {
661 				if (states[i] != 0) {
662 					noOtherKeyPressed = false;
663 					break;
664 				}
665 			}
666 
667 			if (noOtherKeyPressed) {
668 				BMessenger deskbar("application/x-vnd.Be-TSKB");
669 				if (deskbar.IsValid())
670 					deskbar.SendMessage('BeMn');
671 			}
672 		}
673 
674 		if (keycode < 256) {
675 			if (isKeyDown)
676 				states[(keycode) >> 3] |= (1 << (7 - (keycode & 0x7)));
677 			else
678 				states[(keycode) >> 3] &= (!(1 << (7 - (keycode & 0x7))));
679 		}
680 
681 		if (isKeyDown
682 			&& keycode == 0x34 // DELETE KEY
683 			&& (states[0x5c >> 3] & (1 << (7 - (0x5c & 0x7))))
684 			&& (states[0x5d >> 3] & (1 << (7 - (0x5d & 0x7))))) {
685 			LOG("TeamMonitor called\n");
686 
687 			// show the team monitor
688 			if (owner->fTMWindow == NULL)
689 				owner->fTMWindow = new (std::nothrow) TMWindow();
690 
691 			if (owner->fTMWindow != NULL) {
692 				owner->fTMWindow->Enable();
693 
694 				// cancel timer only for R5
695 				if (ioctl(device->fd, KB_CANCEL_CONTROL_ALT_DEL, NULL) == B_OK)
696 					LOG("KB_CANCEL_CONTROL_ALT_DEL : OK\n");
697 			}
698 		}
699 
700 		uint32 modifiers = keymap->Modifier(keycode);
701 		if (modifiers
702 			&& (!(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
703 				|| isKeyDown)) {
704 			BMessage *msg = new BMessage;
705 			if (msg == NULL)
706 				continue;
707 
708 			msg->AddInt64("when", timestamp);
709 			msg->what = B_MODIFIERS_CHANGED;
710 			msg->AddInt32("be:old_modifiers", device->modifiers);
711 
712 			if ((isKeyDown && !(modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK)))
713 				|| (isKeyDown && !(device->modifiers & modifiers)))
714 				device->modifiers |= modifiers;
715 			else
716 				device->modifiers &= ~modifiers;
717 
718 			msg->AddInt32("modifiers", device->modifiers);
719 			msg->AddData("states", B_UINT8_TYPE, states, 16);
720 
721 			if (owner->EnqueueMessage(msg)!=B_OK)
722 				delete msg;
723 
724 			if (modifiers & (B_CAPS_LOCK | B_NUM_LOCK | B_SCROLL_LOCK))
725 				owner->_SetLeds(device);
726 		}
727 
728 		uint8 newDeadKey = 0;
729 		if (activeDeadKey == 0)
730 			newDeadKey = keymap->IsDeadKey(keycode, device->modifiers);
731 
732 		if (newDeadKey == 0) {
733 			char *string = NULL, *rawString = NULL;
734 			int32 numBytes = 0, rawNumBytes = 0;
735 			keymap->GetChars(keycode, device->modifiers, activeDeadKey, &string, &numBytes);
736 			keymap->GetChars(keycode, 0, 0, &rawString, &rawNumBytes);
737 
738 			BMessage *msg = new BMessage;
739 			if (msg == NULL)
740 				continue;
741 
742 			if (numBytes > 0)
743 				msg->what = isKeyDown ? B_KEY_DOWN : B_KEY_UP;
744 			else
745 				msg->what = isKeyDown ? B_UNMAPPED_KEY_DOWN : B_UNMAPPED_KEY_UP;
746 
747 			msg->AddInt64("when", timestamp);
748 			msg->AddInt32("key", keycode);
749 			msg->AddInt32("modifiers", device->modifiers);
750 			msg->AddData("states", B_UINT8_TYPE, states, 16);
751 			if (numBytes > 0) {
752 				for (int i = 0; i < numBytes; i++) {
753 					msg->AddInt8("byte", (int8)string[i]);
754 				}
755 				msg->AddString("bytes", string);
756 
757 				if (rawNumBytes <= 0) {
758 					rawNumBytes = 1;
759 					delete[] rawString;
760 					rawString = string;
761 				} else
762 					delete[] string;
763 
764 				if (isKeyDown && lastKeyCode == keycode) {
765 					repeatCount++;
766 					msg->AddInt32("be:key_repeat", repeatCount);
767 				} else
768 					repeatCount = 1;
769 			} else
770 				delete[] string;
771 
772 			if (rawNumBytes > 0)
773 				msg->AddInt32("raw_char", (uint32)((uint8)rawString[0] & 0x7f));
774 
775 			delete[] rawString;
776 
777 			if (isKeyDown && !modifiers && activeDeadKey != 0
778 				&& device->input_method_started) {
779 				// a dead key was completed
780 				device->EnqueueInlineInputMethod(B_INPUT_METHOD_CHANGED,
781 					string, true, msg);
782 			} else if (owner->EnqueueMessage(msg) != B_OK)
783 				delete msg;
784 		} else if (isKeyDown) {
785 			// start of a dead key
786 			if (device->EnqueueInlineInputMethod(B_INPUT_METHOD_STARTED) == B_OK) {
787 				char *string = NULL;
788 				int32 numBytes = 0;
789 				keymap->GetChars(keycode, device->modifiers, 0, &string, &numBytes);
790 
791 				if (device->EnqueueInlineInputMethod(B_INPUT_METHOD_CHANGED, string) == B_OK)
792 					device->input_method_started = true;
793 			}
794 		}
795 
796 		if (!isKeyDown && !modifiers) {
797 			if (activeDeadKey != 0) {
798 				device->EnqueueInlineInputMethod(B_INPUT_METHOD_STOPPED);
799 				device->input_method_started = false;
800 			}
801 
802 			activeDeadKey = newDeadKey;
803 		}
804 
805 		lastKeyCode = isKeyDown ? keycode : 0;
806 	}
807 
808 	return 0;
809 }
810 
811 
812 void
813 KeyboardInputDevice::_RecursiveScan(const char *directory)
814 {
815 	CALLED();
816 	BEntry entry;
817 	BDirectory dir(directory);
818 	while (dir.GetNextEntry(&entry) == B_OK) {
819 		BPath path;
820 		entry.GetPath(&path);
821 		if (entry.IsDirectory())
822 			_RecursiveScan(path.Path());
823 		else
824 			_AddDevice(path.Path());
825 	}
826 }
827 
828 
829 void
830 KeyboardInputDevice::_SetLeds(keyboard_device *device)
831 {
832 	if (device->fd < 0)
833 		return;
834 
835 	uint32 locks = device->modifiers;
836 	char lock_io[3];
837 	memset(lock_io, 0, sizeof(lock_io));
838 	if (locks & B_NUM_LOCK)
839 		lock_io[0] = 1;
840 	if (locks & B_CAPS_LOCK)
841 		lock_io[1] = 1;
842 	if (locks & B_SCROLL_LOCK)
843 		lock_io[2] = 1;
844 
845 	ioctl(device->fd, KB_SET_LEDS, &lock_io);
846 }
847 
848 
849 //	#pragma mark -
850 
851 
852 keyboard_device::keyboard_device(const char *path)
853 	: BHandler("keyboard device"),
854 	owner(NULL),
855 	fd(-1),
856 	device_watcher(-1),
857 	active(false),
858 	input_method_started(false)
859 {
860 	strcpy(this->path, path);
861 	device_ref.name = get_short_name(path);
862 	device_ref.type = B_KEYBOARD_DEVICE;
863 	device_ref.cookie = this;
864 
865 	isAT = strstr(path, "keyboard/at") != NULL;
866 
867 	if (be_app->Lock()) {
868 		be_app->AddHandler(this);
869 		be_app->Unlock();
870 	}
871 }
872 
873 
874 keyboard_device::~keyboard_device()
875 {
876 	free(device_ref.name);
877 
878 	if (be_app->Lock()) {
879 		be_app->RemoveHandler(this);
880 		be_app->Unlock();
881 	}
882 }
883 
884 
885 status_t
886 keyboard_device::EnqueueInlineInputMethod(int32 opcode,
887 	const char* string, bool confirmed, BMessage* keyDown)
888 {
889 	BMessage* message = new BMessage(B_INPUT_METHOD_EVENT);
890 	if (message == NULL)
891 		return B_NO_MEMORY;
892 
893 	message->AddInt32("be:opcode", opcode);
894 	message->AddBool("be:inline_only", true);
895 
896 	if (string != NULL)
897 		message->AddString("be:string", string);
898 	if (confirmed)
899 		message->AddBool("be:confirmed", true);
900 	if (keyDown)
901 		message->AddMessage("be:translated", keyDown);
902 	if (opcode == B_INPUT_METHOD_STARTED)
903 		message->AddMessenger("be:reply_to", this);
904 
905 	status_t status = owner->EnqueueMessage(message);
906 	if (status != B_OK)
907 		delete message;
908 
909 	return status;
910 }
911 
912 
913 void
914 keyboard_device::MessageReceived(BMessage *message)
915 {
916 	if (message->what != B_INPUT_METHOD_EVENT) {
917 		BHandler::MessageReceived(message);
918 		return;
919 	}
920 
921 	int32 opcode;
922 	if (message->FindInt32("be:opcode", &opcode) != B_OK)
923 		return;
924 
925 	if (opcode == B_INPUT_METHOD_STOPPED)
926 		input_method_started = false;
927 }
928 
929