1 /** 2 * Consoleur: a package for interaction with character-oriented terminal emulators 3 * 4 * Copyright: Maxim Freck, 2017. 5 * Authors: Maxim Freck <maxim@freck.pp.ru> 6 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 */ 8 module consoleur.input.types; 9 10 import consoleur.input.util; 11 12 /** 13 * Pressed key type: ascii character, utf-8 characer, command or raw sequence 14 */ 15 enum KeyType 16 { 17 ASCII, 18 UTF8, 19 COMMAND, 20 RAW, 21 } 22 23 24 version(WithSuperKey) { 25 /** 26 * Key modifiers 27 */ 28 enum KeyModifier 29 { 30 none = 0b00000000_00000000_00000000_00000000, 31 shift = 0b00000000_00000000_00000000_00000001, 32 alt = 0b00000000_00000000_00000000_00000010, 33 control = 0b00000000_00000000_00000000_00000100, 34 meta = 0b00000000_00000000_00000000_00001000, 35 supr = 0b00000000_00000000_00000000_00010000, 36 } 37 } else { 38 /** 39 * Key modifiers 40 */ 41 enum KeyModifier 42 { 43 none = 0b00000000_00000000_00000000_00000000, 44 shift = 0b00000000_00000000_00000000_00000001, 45 alt = 0b00000000_00000000_00000000_00000010, 46 control = 0b00000000_00000000_00000000_00000100, 47 meta = 0b00000000_00000000_00000000_00001000, 48 } 49 } 50 51 52 /** 53 * Availabe commands 54 */ 55 enum Command: int 56 { 57 empty = -255, 58 unknown = -1, 59 60 nothing = 0x00, 61 startOfHeading = 0x01, 62 startOfText = 0x02, 63 endOfText = 0x03, 64 endOfTransmission = 0x04, 65 enquiry = 0x05, 66 acknowledge = 0x06, 67 bell = 0x07, 68 backspace = 0x08, 69 horizontalTabulation = 0x09, 70 lineFeed = 0x0a, 71 lineTabulation = 0x0b, 72 formFeed = 0x0c, 73 carriageReturn = 0x0d, 74 shiftOu = 0x0e, 75 shiftIn = 0x0f, 76 dataLinkEscape = 0x10, 77 deviceControlOne = 0x11, 78 deviceControlTwo = 0x12, 79 deviceControlThree = 0x13, 80 deviceControlFour = 0x14, 81 negativeAcknowledge = 0x15, 82 synchronousIdle = 0x16, 83 endOfTransmissionBlock = 0x17, 84 cancel = 0x18, 85 endOfMedium = 0x19, 86 substitute = 0x1a, 87 escape = 0x1b, 88 fileSeparator = 0x1c, 89 groupSeparator = 0x1d, 90 recordSeparator = 0x1e, 91 unitSeparator = 0x1f, 92 del = 0x7f, 93 94 keyUp = 0x5b41, 95 keyDown = 0x5b42, 96 keyRight = 0x5b43, 97 keyLeft = 0x5b44, 98 keyB2 = 0x5b45, 99 100 keyInsert = 0xfe01, 101 keyDelete = 0xfe02, 102 keyHome = 0xfe03, 103 keyEnd = 0xfe04, 104 keyPageUp = 0xfe05, 105 keyPageDown = 0xfe06, 106 107 keyF1 = 0xff01, 108 keyF2 = 0xff02, 109 keyF3 = 0xff03, 110 keyF4 = 0xff04, 111 keyF5 = 0xff05, 112 keyF6 = 0xff06, 113 keyF7 = 0xff07, 114 keyF8 = 0xff08, 115 keyF9 = 0xff09, 116 keyF10 = 0xff0a, 117 keyF11 = 0xff0b, 118 keyF12 = 0xff0c, 119 120 pasteStart = 0xfffffd, 121 pasteEnd = 0xfffffe, 122 123 winch = 0xffffff 124 } 125 126 127 /** 128 * Key value 129 */ 130 union KeyValue 131 { 132 ///ASCII Character 133 char c; 134 ///UTF-8 sequence 2…6 bytes 135 ubyte[6] utf; 136 ///Console command 137 Command code; 138 ///Raw input usualy CSI or SS3 sequence 139 string raw; 140 141 ///constructor 142 this(Command code) @safe { this.code = code; } 143 ///ditto 144 this(char c) @safe { this.c = c; } 145 ///ditto 146 this(ubyte[6] symbol) @safe { this.utf = symbol; } 147 ///ditto 148 this(string raw) @trusted { this.raw = raw; } 149 } 150 151 152 /** 153 * Pressed key 154 */ 155 struct Key 156 { 157 ///Type 158 KeyType type; 159 ///Value depending on type 160 KeyValue content; 161 ///Key modifier 162 uint modifier; 163 164 ///constructor 165 this(KeyType type, KeyValue content, uint modifier = KeyModifier.none) @safe 166 { 167 this.type = type; 168 this.content = content; 169 this.modifier = modifier; 170 } 171 172 /******* 173 * Returns: string representation of the current key 174 * 175 */ 176 string opCast() @trusted 177 { 178 import std.conv: to; 179 string ret; 180 181 if (modifier & KeyModifier.shift) ret ~= "Shift+"; 182 if (modifier & KeyModifier.alt) ret ~= "Alt+"; 183 if (modifier & KeyModifier.control) ret ~= "Ctrl+"; 184 if (modifier & KeyModifier.meta) ret ~= "Meta+"; 185 version(WithSuperKey) if (modifier & KeyModifier.supr) ret ~= "Super+"; 186 187 with (KeyType) final switch(this.type) { 188 case COMMAND: 189 ret ~= to!string(content.code); 190 break; 191 case ASCII: 192 ret ~= cast(string)[content.c]; 193 break; 194 case UTF8: 195 ret ~= cast(string)content.utf[0 .. content.utf[0].codepointLength]; 196 break; 197 case RAW: 198 ret ~= content.raw.escapeString; 199 break; 200 } 201 202 return ret; 203 } 204 } 205