1 module razer.chroma;
2 
3 import std.algorithm;
4 import std.array;
5 import std.range;
6 import std.conv;
7 import std.file;
8 import std.path;
9 import std.string;
10 import std.exception;
11 
12 import razer.hardware;
13 
14 /// A structure representing the size of a chroma device
15 struct Dimension {
16   /// 
17   int width;
18 
19   ///
20   int height;
21 }
22 
23 /// A structure representing a chroma color
24 struct Color {
25   ///
26   ubyte red;
27 
28   ///
29   ubyte green;
30 
31   ///
32   ubyte blue;
33 
34   /// Convert the color to a byte array
35   ubyte[] toArray() {
36     return [red, green, blue];
37   }
38 }
39 
40 /// Return the razer chroma devices that are connected to your computer
41 RazerChromaDevice[] chromaDevices() {
42   return dirEntries("/sys/bus/hid/drivers/razerkbd/", SpanMode.shallow)
43     .filter!(a => buildPath(a, "device_type").exists)
44     .map!(a => new RazerChromaDevice(a))
45     .array;
46 }
47 
48 /// Represents a chroma device and it offers methods for customising
49 /// the led colors
50 class RazerChromaDevice {
51   private {
52     immutable string basePath;
53   }
54 
55   RazerDevice device;
56 
57   alias device this;
58 
59   this(const string basePath) {
60     this.basePath = basePath;
61     this.device = getRazerDevice(basePath.baseName);
62   }
63 
64   ///
65   string country() {
66     return readText(buildPath(basePath, "country")).strip;
67   }
68 
69   /// 
70   string type() {
71     return readText(buildPath(basePath, "device_type")).strip;
72   }
73   
74   ///
75   string serial() {
76     return readText(buildPath(basePath, "device_serial")).strip;
77   }
78   
79   ///
80   string mode() {
81     return readText(buildPath(basePath, "device_mode")).strip;
82   }
83   
84   ///
85   string firmwareVersion() {
86     return readText(buildPath(basePath, "firmware_version")).strip;
87   }
88 
89   /// check if the razer logo is illuminated
90   bool logoLedState() {
91     return readText(buildPath(basePath, "logo_led_state")).strip == "1";
92   }
93 
94   ///
95   string driverVersion() {
96     return readText(buildPath(basePath, "version")).strip;
97   }
98 
99   /// set a row of colors
100   void setKeyRow(ubyte row, Color[] colors) {
101     enforce(device.hasMatrix, "The device does not support custom effects.");
102     enforce(device.height >= row, "The row is too large.");
103     enforce(device.width >= colors.length, "The color list is too large.");
104 
105     ubyte[] colorList = colors.map!"a.toArray".join;
106     ubyte[] list = [ row, 0, colors.length - 1 ].to!(ubyte[]).chain(colorList).array;
107 
108     std.file.write(buildPath(basePath, "matrix_custom_frame"), list);
109   }
110 
111   /// apply the custom effect
112   void flush() {
113     enforce(device.hasMatrix, "The device does not support custom effects.");
114     std.file.write(buildPath(basePath, "matrix_effect_custom"), "1");
115   }
116 }