g810-led
g810-led copied to clipboard
Supporting local characters
I'd like to be able to set the color of the keys of my Nordic keyboard (I'm Danish, so I use 'æ', 'ø', and 'å' a lot. However, I have to specify other keynames to set those keys.
My wish is to be able to specify, e.g. g810-led -k æ ff0000
I'd like to help by writing and testing the actual code, but thought it might be good to discuss how to generalise this best. Can we get the key mapping for a character from the driver, for example?
There was just a discussion regarding this a few days ago, and it appears that Logitech doesn't actually make it easy/possible to distinguish between the different keyboard layouts. What likely needs to be done is that we need some way of telling the software what keyboard layout is being used, and set up the key mapping based on that.
Yes, I thought perhaps this could be derived from the OS?
At this time, I don't have idea how handle this... Make an argument but it's not very usefull and need a full mapping table. If I can found the keymap from USB infos and not OS, it's a possible way...
So the quick fix is to just add them to the list as aliases?
Or if we can detect the variant by any means, we could map according to that.....
The problem I see with aliases is that there are keys that are shared across the layouts, but have (as far as I know) different internal IDs (such as the - key, in US it is up in the number row, in the FR layout it is near the right shift key). Without knowing which layout is specifically being used, how would we handle the key name.
I am thinking that we could just default to US as we do now, but provide a flag that triggers the aliases based on the layout. It wouldn't be as clean as what is currently in place, but it would allow for localization. Basically, we would just add some code at the top of Keyboard::parseKey that does something like
if(layout != "US" && (key == "minus" || key == "-")) key = "slash";
and then add a -layout=X command line option
Also, if this helps for automated parsing, the full output from lsusb for my keyboard is as follows (maybe we can find some difference between US and QWERTZ...)
lsusb -v -d 046d:c331
Bus 001 Device 005: ID 046d:c331 Logitech, Inc.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x046d Logitech, Inc.
idProduct 0xc331
bcdDevice 2.00
iManufacturer 1 Logitech
iProduct 2 Gaming Keyboard G810
iSerial 3 036635553130
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 59
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 4 U102.00_B0014
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 1 Boot Interface Subclass
bInterfaceProtocol 1 Keyboard
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 65
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 119
Report Descriptors:
** UNAVAILABLE **
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
Diff from my CH keyboard :
bcdDevice 2.00 bcdDevice 2.03 iSerial 3 036635553130 iSerial 3 0287355D3938 iConfiguration 4 U102.00_B0014 iConfiguration 4 U102.03_B0027
Diff from my Nordic keyboard:
bcdDevice 2.00 bcdDevice 2.03 iSerial 3 036635553130 iSerial 3 118735743830 iConfiguration 4 U102.00_B0014 iConfiguration 4 U102.03_B0027
So we have three different iSerial #:
Nordic: 3 118735743830 Swiss: 3 0287355D3938 US (?): 3 036635553130
iSerial must be unique for each keyboard ... bcdDevice seem to be the firmware version iConfiguration seem related to firmware version to.
Yeah, so I guess @meisanerd has the best idea for now: a layoutparameter....
Mappingtable for German QWERTZ 105 key layout (Diffrences only).
Name | Symbol | German Layout | Symbol |
---|---|---|---|
tilde | ~ | Zirkumflex | ^ |
minus | - | Fragezeichen | ? |
equal | = | Gravis | ` |
open_bracket | [ | Ue | Ü |
close_bracket | ] | Plus | + |
semicolon | ; | Oe | Ö |
quote | ' | Ae | Ä |
dollar | $ | Raute | # |
intl_backslash | \ | Pipe | | |
slash | / | Minus | - |
num_period | . | Numpad Komma | , |
May you could add it to your project wiki.
@addictedtoberlin Thank for the mapping table. Wiki is a possible way but it's best to have access from the command line. I will try to find a good solution, just need time.
It seems that there are only three options ... A parameter, use of system keymap or make a help page for keymap The three options require mapping table What is the best way ??? Need to find a keymap strategy
Based on the logitech LED SDK that was released and the python wrappers that were released with them, we should keep the base characters consistent with the english model - and provide aliases for hem them. If we have to, we can add separate 'layout' command line arguments.
There are several ways to detect keyboards, but I think that's possibly a much longer term fix, as it requires more research.
I would suggest a g810-led/layouts subdirectory, with layouts/
We could use setxkbmap to detect the current layout, and use that. We would then just have to map out all of the possible layouts and add them one at a time. Having a layout parameter to manually override that wouldn't be a bad idea either, and the support code would all be the same.
Here is a code sample that I found that should give us the detection code: http://cboard.cprogramming.com/linux-programming/169388-detect-keyboard-layout-linux.html#post1248447
Once we have that in place and working it should be a simple matter to just set up aliases in the parseKey function. Something like:
if(KBD_LAYOUT=="quertz" && key == "zirkumflex") key = "tilde";
I absolutely don't think we should drag x11 utilities into this.
Upon further research, there's two possibilities I'd like to look further into:
- Some of the 'unavailable' information in the text output provided by lsusb might have actual data in it if we try and parse it ourselves. I would hope for a product number akin to what's in the following point. I'll try and look into the unavailable data fields later this week to see if they spit something out.
- the logitech product numbers - which should be per version that they sell. They may not be readily available from the lsusb, but the consumers should know them fairly easily. I tried to just get a dump of the available layouts for the g810, but logitech will only show me the English version >.> (Black, English: 920-007739)
(2) still winds up requiring us to provide layouts. Which is fine - but it does mean that people who want their layout included are going to need to commit that file.
As per the lsusb dump and comparison above, the only differences we found between the keyboards were the serial number and the firmware version. The physical layout does not appear to be defined by Logitech at all, which is why we are looking for alternate solutions.
My suggestion to try to parse the output from setxkbmap was so that we don't have to ask the user to specify the layout or model number, it would just attempt to detect it on its own. If done properly, there would be no hard requirement for x11 utilities, but it would simplify user setup if they did happen to already have it installed. I figure x11 is a better option than Gnome/KDE/XFCE/whatever as it will likely be in place for the majority of the users.
For reference, the product number on my G810 is 820-007620
I understand that point meisanerd - but my point is that the data like this:
wDescriptorLength 65 Report Descriptors: ** UNAVAILABLE **
is unrendered possibly because there's no specific format for it (and just dumping hex to screen would be... bad). We might find model in there. Or we just have people look at the back of their boards. This configuration pattern:
iConfiguration 4 U102.03_B0027
is in the format U(FIRMWARE)_B(M/N #), where you can find the M/N# on the back faceplate of your keyboard.
e.g. http://cdn.gamer-network.net/2016/usgamer/Logitech-G810-Shot-07.jpg
We do not need to bring in x11, or any of the other options, when the majority of users would be better served by just manually reporting their need to the interface we're writing. You do not want the resulting dependency chain and build hell and problem reports that are generated from linking to these software packages. But that's just my opinion.
I am not sure that the iConfiguration is in that format, as my M/N is Y-U0027, but the iConfiguration value is U102.00_B0014
Also, if we use the code I linked above, there is no dependency upon x11. What it does is attempts to execute the x11 app and parse the return value. If the app is not installed, there would be nothing to parse, and it would fall back to other methods or the default layout. I am just trying to make it simpler for the general public to be able to use this, so they don't have to go digging through code and do special defines. The best option (in my opinion) is to make it easy enough that they can go into their package manager, install the G810 driver package, and have their keyboard work using their local layout.
I have re-run lsusb with the keyboard unbound to get the values for those Report Descriptors. Here is the output:
lsusb -v -d 046d:c331
Bus 001 Device 004: ID 046d:c331 Logitech, Inc.
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x046d Logitech, Inc.
idProduct 0xc331
bcdDevice 2.00
iManufacturer 1 Logitech
iProduct 2 Gaming Keyboard G810
iSerial 3 036635553130
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 59
bNumInterfaces 2
bConfigurationValue 1
iConfiguration 4 U102.00_B0014
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 500mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 1 Boot Interface Subclass
bInterfaceProtocol 1 Keyboard
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 65
Report Descriptor: (length is 65)
Item(Global): Usage Page, data= [ 0x01 ] 1
Generic Desktop Controls
Item(Local ): Usage, data= [ 0x06 ] 6
Keyboard
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Usage Page, data= [ 0x07 ] 7
Keyboard
Item(Local ): Usage Minimum, data= [ 0xe0 ] 224
Control Left
Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
GUI Right
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x08 ] 8
Item(Main ): Input, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Count, data= [ 0x01 ] 1
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Main ): Input, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Count, data= [ 0x03 ] 3
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Usage Page, data= [ 0x08 ] 8
LEDs
Item(Local ): Usage Minimum, data= [ 0x01 ] 1
NumLock
Item(Local ): Usage Maximum, data= [ 0x03 ] 3
Scroll Lock
Item(Main ): Output, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Count, data= [ 0x05 ] 5
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Main ): Output, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Count, data= [ 0x06 ] 6
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
Item(Global): Usage Page, data= [ 0x07 ] 7
Keyboard
Item(Local ): Usage Minimum, data= [ 0x00 ] 0
No Event
Item(Local ): Usage Maximum, data= [ 0xff 0x00 ] 255
(null)
Item(Main ): Input, data= [ 0x00 ] 0
Data Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0008 1x 8 bytes
bInterval 1
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 3 Human Interface Device
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
HID Device Descriptor:
bLength 9
bDescriptorType 33
bcdHID 1.11
bCountryCode 0 Not supported
bNumDescriptors 1
bDescriptorType 34 Report
wDescriptorLength 119
Report Descriptor: (length is 119)
Item(Global): Usage Page, data= [ 0x01 ] 1
Generic Desktop Controls
Item(Local ): Usage, data= [ 0x06 ] 6
Keyboard
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Usage Page, data= [ 0x07 ] 7
Keyboard
Item(Local ): Usage Minimum, data= [ 0x00 ] 0
No Event
Item(Local ): Usage Maximum, data= [ 0xe7 ] 231
GUI Right
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xe7 0x00 ] 231
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x14 ] 20
Item(Global): Report ID, data= [ 0x01 ] 1
Item(Main ): Input, data= [ 0x00 ] 0
Data Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Item(Global): Usage Page, data= [ 0x0c ] 12
Consumer
Item(Local ): Usage, data= [ 0x01 ] 1
Consumer Control
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Report ID, data= [ 0x02 ] 2
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0x01 ] 1
Item(Global): Report Size, data= [ 0x01 ] 1
Item(Global): Report Count, data= [ 0x07 ] 7
Item(Local ): Usage, data= [ 0xb5 ] 181
Scan Next Track
Item(Local ): Usage, data= [ 0xb6 ] 182
Scan Previous Track
Item(Local ): Usage, data= [ 0xb7 ] 183
Stop
Item(Local ): Usage, data= [ 0xcd ] 205
Play/Pause
Item(Local ): Usage, data= [ 0xe9 ] 233
Volume Increment
Item(Local ): Usage, data= [ 0xea ] 234
Volume Decrement
Item(Local ): Usage, data= [ 0xe2 ] 226
Mute
Item(Main ): Input, data= [ 0x02 ] 2
Data Variable Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Global): Report Count, data= [ 0x01 ] 1
Item(Main ): Input, data= [ 0x01 ] 1
Constant Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Item(Global): Usage Page, data= [ 0x43 0xff ] 65347
(null)
Item(Local ): Usage, data= [ 0x02 0x06 ] 1538
(null)
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Report ID, data= [ 0x11 ] 17
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x13 ] 19
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
Item(Local ): Usage, data= [ 0x02 ] 2
(null)
Item(Main ): Input, data= [ 0x00 ] 0
Data Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0x02 ] 2
(null)
Item(Main ): Output, data= [ 0x00 ] 0
Data Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Item(Global): Usage Page, data= [ 0x43 0xff ] 65347
(null)
Item(Local ): Usage, data= [ 0x04 0x06 ] 1540
(null)
Item(Main ): Collection, data= [ 0x01 ] 1
Application
Item(Global): Report ID, data= [ 0x12 ] 18
Item(Global): Report Size, data= [ 0x08 ] 8
Item(Global): Report Count, data= [ 0x3f ] 63
Item(Global): Logical Minimum, data= [ 0x00 ] 0
Item(Global): Logical Maximum, data= [ 0xff 0x00 ] 255
Item(Local ): Usage, data= [ 0x04 ] 4
(null)
Item(Main ): Input, data= [ 0x00 ] 0
Data Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Local ): Usage, data= [ 0x04 ] 4
(null)
Item(Main ): Output, data= [ 0x00 ] 0
Data Array Absolute No_Wrap Linear
Preferred_State No_Null_Position Non_Volatile Bitfield
Item(Main ): End Collection, data=none
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 1
The proper example you posted has quite a bit of dependency on X11. The first listed (using popen) is a huge security risk given that I run this command with sudo, as do many others - especially those that aren't allowed to use systemd / udev commands thanks to security protocols at their installations. If the group decides to go with that, then let it be known.
Thanks for the extended report.
Another problem that should not be forgotten is the profile files A possibility is to add a line that define charset of the file
Very hard to find a solution, we need a full keymap for all key of the keyboard... You can have QWERTY, QWERTZ, AZERTY, .... all keys can be impacted :(
I think the profile file is a good place to put this. How often does one change keyboard?
@MatMoul it's probably best to keep this to physical key identifiers and not worry about what people are calling their own keys - people can submit images of their keyboard physical layouts and appropriate key translations, and we can build profile style files out of that?
Hi all, sorry for bothering you today, I was looking through the Logitech files and I found this:
{
"Logitech.Gaming.Keyboard.G710" :
{
"default" : "INTL",
"US" : "0x0409",
"DEU" : "0x0407",
"UK" : "0x0809",
"RU" : "0x0419",
"FRA" : "0x040c",
"SW" :
[
"0x040c100c",
"0x100c100c",
"0x04070807",
"0x08070807"
],
"TUR" : "0x041f",
"NORDIC" :
[
"0x0406",
"0x0414",
"0x0814",
"0x041d",
"0x040b"
],
"KOR" : "0x0412",
"JPN" : "0x0411",
"CHT" : "0x0404"
},
"Logitech.Gaming.Keyboard.G510s" :
{
"default" : "INTL",
"US" : "0x0409",
"DEU" : "0x0407",
"UK" : "0x0809",
"RU" : "0x0419",
"FRA" : "0x040c",
"SW" :
[
"0x040c100c",
"0x100c100c",
"0x04070807",
"0x08070807"
],
"TUR" : "0x041f",
"NORDIC" :
[
"0x0406",
"0x0414",
"0x0814",
"0x041d",
"0x040b"
],
"KOR" : "0x0412",
"JPN" : "0x0411",
"CHT" : "0x0404"
},
"Logitech.Gaming.Keyboard.G19s" :
{
"default" : "INTL",
"US" : "0x0409",
"DEU" : "0x0407",
"UK" : "0x0809",
"RU" : "0x0419",
"FRA" : "0x040c",
"SW" :
[
"0x040c100c",
"0x100c100c",
"0x04070807",
"0x08070807"
],
"TUR" : "0x041f",
"NORDIC" :
[
"0x0406",
"0x0414",
"0x0814",
"0x041d",
"0x040b"
],
"KOR" : "0x0412",
"JPN" : "0x0411",
"CHT" : "0x0404"
},
"Logitech.Gaming.Keyboard.G105" :
{
"default" : "INTL",
"US" : "0x0409",
"DEU" : "0x0407",
"UK" : "0x0809",
"RU" : "0x0419",
"FRA" : "0x040c",
"SW" :
[
"0x040c100c",
"0x100c100c",
"0x04070807",
"0x08070807"
],
"TUR" : "0x041f",
"NORDIC" :
[
"0x0406",
"0x0414",
"0x0814",
"0x041d",
"0x040b"
],
"KOR" : "0x0412",
"JPN" : "0x0411",
"CHT" : "0x0404"
},
"Logitech.Gaming.Devio.Keyboard" :
{
"default" : "INTL",
"US" : "0x01",
"INTL" : "0x02",
"UK" : "0x03",
"DEU" : "0x04",
"FRA" : "0x05",
"RU" : "0x07",
"NORDIC" : "0x08",
"KOR" : "0x09",
"JPN" : "0x0a",
"CHT" : "0x0b",
"SW" : "0x0d",
"TUR" : "0x0e",
"ESP": "0x0f",
"THAI" : "0x33",
"INTL2" : "0x37"
}
}
I think the last one Logitech.Gaming.Devio.Keyboard
is the one we should focus on, another thing is that when tracing the whireshark dumps, there is no trace of the serial number, I'm still scratching my head and trying to figure out how the Logitech Software detects the layout within these few first calls with the keyboard. without getting the serial number. I still think that the serial number is our best choice to discover the layout, or maybe I'm wrong.
Anyways I've added my serial to the other three serials I found up here, in the hope that someone will have a eureka moment and figure it all out.
107D35743231 0x03 UK 118735743830 0x08 Nordic 0287355D3938 0x0d Swiss 036635553130 0x01 US (Not sure)
if anyone else can provide his/her serial, that would be great.
I don't think that the serial is the key to all this. But here's the serial number of my German G910 107035573737
In my wireshark dumps is a "GET DESCRIPTOR Response CONFIGURATION" with an iConfiguration of 4. That would fit the list @MohamadSaada provided.
Hello everyone,
I am not very good with c++ so I created my python frontend. As I saw this issue I come up with one idea and coded it for my python fronted.
Basically, idea is:
- have one constant xmodmap -pke output for us keyboard
- on first run, run xmodmap -pke for current layout (in my case, I tested it with croatian)
- recognize the differences in layouts
- query user to press keys that differe
- save that differences for remaping
- on key color change, see if the key is in remap keys
My code is here https://github.com/spiritg9/g810-led-python-frontend when you git clone repository, you can try this and test with running first run: ./keyboard.py diff after that try for example: ./keyboard.py key č ff0000 where č is your layout key (without shift, small caps)
If you like the idea, ti would be great if somebody would acctually code it for g810-led original project, I would be glad to help with that.
@spiritg9 Thanks for your return but xmodmap is dependent of xorg and g810-led must not have this dependency... Currently, g810-led run in ~60ms and I try to maintain this speed.
I'm really new to this kind of thing and I have the Japanese "Logicool" G810 QWERTY keyboard which not only has a different key layout, but also has 5 additional keys. If someone could give me a simple tutorial to assist me in giving the information required, I would very much appreciate it.