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