Class: KeyCoder

Inherits:
Object
  • Object
show all
Defined in:
ext/accessibility/key_coder/key_coder.c,
ext/accessibility/key_coder/key_coder.c

Overview

Class that encapsulates some low level work for finding key code mappings and posting keyboard events to the system.

Class Method Summary collapse

Class Method Details

.dynamic_mappingHash{String=>Number}

Generate the mapping of characters to key codes for keys that can be remapped based on keyboard layout. Changing the keyboard layout at runtime will cause the returned hash to be different.

Examples:


KeyCoder.dynamic_mapping  => { "a" => 0, "b" => 24, ... }

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'ext/accessibility/key_coder/key_coder.c', line 29

static
VALUE
keycoder_dynamic_mapping()
{

  VALUE map = rb_hash_new();

#ifdef NOT_MACRUBY
  @autoreleasepool {
#endif

  TISInputSourceRef keyboard = TISCopyCurrentKeyboardLayoutInputSource();
  CFDataRef layout_data = (CFDataRef)TISGetInputSourceProperty(keyboard, kTISPropertyUnicodeKeyLayoutData);
  const UCKeyboardLayout* layout = (const UCKeyboardLayout*)CFDataGetBytePtr(layout_data);

  void (^key_coder)(int) = ^(int key_code) {
    UniChar      string[255];
    UniCharCount string_length = 0;
    UInt32       dead_key_state = 0;
    UCKeyTranslate(
		   layout,
       key_code,
		   kUCKeyActionDown,
		   0,
		   LMGetKbdType(),  // kb type
		   0,               // OptionBits keyTranslateOptions,
		   &dead_key_state,
		   255,
		   &string_length,
		   string
		  );

    NSString* nsstring = [NSString stringWithCharacters:string length:string_length];
    rb_hash_aset(map, rb_str_new_cstr([nsstring UTF8String]), INT2FIX(key_code));
  };

  // skip 65-92 since they are hard coded and do not change
  for (int key_code = 0;  key_code < 65;  key_code++)
    key_coder(key_code);
  for (int key_code = 93; key_code < 127; key_code++)
    key_coder(key_code);

#ifdef NOT_MACRUBY
  CFRelease(keyboard);
  }; // Close the autorelease pool
#else
  CFMakeCollectable(keyboard);
#endif

  return map;
}

.post_event(event) ⇒ true

Post the given event to the system and return true. This method will also add a small (9000 microsecond) delay after posting to ensure that keyboard actions do not go too fast.

Examples:


KeyCoder.post_event [0, true]  -> true

95
96
97
98
99
100
101
102
103
104
105
106
107
# File 'ext/accessibility/key_coder/key_coder.c', line 95

static
VALUE
keycoder_post_event(VALUE self, VALUE event)
{
  VALUE code  = rb_ary_entry(event, 0);
  VALUE state = rb_ary_entry(event, 1);

  CGEventRef event_ref = CGEventCreateKeyboardEvent(NULL, FIX2LONG(code), state);
  CGEventPost(kCGHIDEventTap, event_ref);

  usleep(9000); // 9000 is a magic number
  return Qtrue;
}