[{"data":1,"prerenderedAt":590},["ShallowReactive",2],{"\u002Fblog\u002Fgetting-the-function-keys-back-on-a-realme-book-i5":3,"surround:\u002Fblog\u002Fgetting-the-function-keys-back-on-a-realme-book-i5":584},{"id":4,"title":5,"author":6,"body":7,"date":562,"description":563,"extension":564,"head":565,"image":21,"keywords":566,"meta":577,"navigation":271,"ogImage":565,"path":578,"published":271,"robots":579,"seo":580,"sitemap":581,"stem":582,"__hash__":583},"blog\u002Fblog\u002Fgetting-the-function-keys-back-on-a-realme-book-i5.md","Getting the Function Keys Back on a Realme Book i5","Jan Tolentino",{"type":8,"value":9,"toc":552},"minimark",[10,14,22,33,44,49,63,66,70,73,76,82,86,89,92,99,127,138,142,149,154,161,411,415,426,441,444,514,518,525,528,536,539,548],[11,12,5],"h1",{"id":13},"getting-the-function-keys-back-on-a-realme-book-i5",[15,16,17],"p",{},[18,19],"img",{"alt":20,"src":21},"Close-up of a laptop keyboard","https:\u002F\u002Fimages.pexels.com\u002Fphotos\u002F4065748\u002Fpexels-photo-4065748.jpeg",[15,23,24,25,32],{},"A few years ago, I bought a ",[26,27,31],"a",{"href":28,"rel":29},"https:\u002F\u002Fwww.realme.com\u002Fph\u002Frealme-book",[30],"nofollow","Realme Book i5"," for work. I bought it because it was slim, the display was nice, and it was a great lightweight machine to work on away from my desk.",[15,34,35,36,40,41,43],{},"There was one problem I didn't expect. I use it mostly to write code, which means I constantly use the F1–F12 keys. On this laptop, the top row defaults to media keys, and I can't trigger the real F-keys without holding the ",[37,38,39],"code",{},"Fn"," key. Unlike laptops from Lenovo that let you flip an ",[37,42,39],{}," lock, this laptop has no such option.",[45,46,48],"h2",{"id":47},"working-around-this-friction","Working around this friction",[15,50,51,52,55,56,59,60,62],{},"My first thought was to remap the keys with ",[37,53,54],{},"evremap",". But this wasn't as easy as I thought. When I checked for raw input with ",[37,57,58],{},"evtest",", the F1 to F12 keys didn't send any events at all unless the ",[37,61,39],{}," key was held down.",[15,64,65],{},"This was disappointing, so I opted to remap a few Fn keys that I use frequently—such as F12 to trigger \"find references\" in my IDE. Often, I'd just resort to working with an external keyboard when necessary.",[45,67,69],{"id":68},"digging-into-the-firmware","Digging into the firmware",[15,71,72],{},"Nonetheless, I was convinced that a toggle existed somewhere, because inside the UEFI setup screen, the F-keys behave like normal F-keys by default. My theory was that once the kernel loads during boot, something flips them to media mode. That led me to suspect the firmware.",[15,74,75],{},"At that point, I browsed for the BIOS file online, decompiled it, and read through the disassembly manually, looking for the flag that set the top-row mode. Given that I had no idea what to look for in the first place, I never found it, even after searching for a bunch of strings I suspected might be related. Eventually, I shelved the project and moved on.",[15,77,78],{},[18,79],{"alt":80,"src":81},"UEFI variable list from RU.EFI with the Setup variable highlighted","blogs\u002Fgetting-the-function-keys-back-on-a-realme-book-i5-01.png",[45,83,85],{"id":84},"picking-it-back-up-with-claude-code","Picking it back up with Claude Code",[15,87,88],{},"I came back to it recently with Claude Code and my old archived dump. Hoping it could help me find what I was looking for, I pointed it at the extracted files, let it review everything I had, and had it work through the ACPI tables.",[15,90,91],{},"After a few hours of going back and forth, it finally landed on something that actually made sense.",[15,93,94,95,98],{},"Over the course of this, I learned that flashing the BIOS was not an option since the firmware is signed and protected. But I didn't actually need to touch the firmware. Instead, Linux can load custom ACPI tables from the ",[37,96,97],{},"initramfs"," at boot and apply the override I needed. That was good enough for me.",[15,100,101,102,104,105,108,109,112,113,116,117,108,120,112,123,126],{},"From Claude Code's investigation, we gathered that the EC exposes three fields that control the ",[37,103,39],{}," key behavior: ",[37,106,107],{},"FNSP",", ",[37,110,111],{},"FNRV",", and ",[37,114,115],{},"MFNM",". Setting them to ",[37,118,119],{},"FNSP = 0",[37,121,122],{},"FNRV = 1",[37,124,125],{},"MFNM = 0"," forces the standard F-key mode. It took quite a while to find the right combo to finally get this behavior.",[15,128,129,130,133,134,137],{},"Now, the plan was to write those values at boot through a supplemental SSDT. To apply this, we create a dummy device in the system bus (",[37,131,132],{},"\\_SB",") with its own ",[37,135,136],{},"_INI"," method. During the initialization phase, this custom device will run its method and flip the EC fields.",[45,139,141],{"id":140},"the-fix","The fix",[15,143,144,145,148],{},"First, note that the kernel needs a ",[37,146,147],{},"CONFIG_ACPI_TABLE_UPGRADE"," configuration enabled.",[150,151,153],"h3",{"id":152},"write-the-ssdt","Write the SSDT",[15,155,156,157,160],{},"Create a new file and name it ",[37,158,159],{},"fnfix.dsl",":",[162,163,168],"pre",{"className":164,"code":165,"language":166,"meta":167,"style":167},"language-c shiki shiki-themes github-light-default github-dark-default","DefinitionBlock (\"\", \"SSDT\", 2, \"REALME\", \"FNFIX\", 0x00000001)\n{\n    \u002F\u002F Reference the existing Embedded Controller and its fields\n    External (\\_SB.PC00.LPCB.H_EC, DeviceObj)\n    External (\\_SB.PC00.LPCB.H_EC.FNSP, FieldUnitObj)\n    External (\\_SB.PC00.LPCB.H_EC.FNRV, FieldUnitObj)\n    External (\\_SB.PC00.LPCB.H_EC.MFNM, FieldUnitObj)\n\n    Scope (\\_SB)\n    {\n        Device (FNFX)\n        {\n            Name (_HID, \"REAL0001\") \u002F\u002F Custom Hardware ID\n            \n            \u002F\u002F Runs once during ACPI initialization\n            Method (_INI, 0, NotSerialized)\n            {\n                \\_SB.PC00.LPCB.H_EC.FNSP = 0\n                \\_SB.PC00.LPCB.H_EC.FNRV = 1\n                \\_SB.PC00.LPCB.H_EC.MFNM = 0\n            }\n        }\n    }\n}\n\n","c","",[37,169,170,220,226,233,242,250,258,266,273,282,288,297,303,321,327,333,348,354,366,377,387,393,399,405],{"__ignoreMap":167},[171,172,175,179,183,187,189,192,194,198,200,203,205,208,210,214,217],"span",{"class":173,"line":174},"line",1,[171,176,178],{"class":177},"sbjLL","DefinitionBlock",[171,180,182],{"class":181},"s4rv2"," (",[171,184,186],{"class":185},"sSVrQ","\"\"",[171,188,108],{"class":181},[171,190,191],{"class":185},"\"SSDT\"",[171,193,108],{"class":181},[171,195,197],{"class":196},"sHrmB","2",[171,199,108],{"class":181},[171,201,202],{"class":185},"\"REALME\"",[171,204,108],{"class":181},[171,206,207],{"class":185},"\"FNFIX\"",[171,209,108],{"class":181},[171,211,213],{"class":212},"sjeE4","0x",[171,215,216],{"class":196},"00000001",[171,218,219],{"class":181},")\n",[171,221,223],{"class":173,"line":222},2,[171,224,225],{"class":181},"{\n",[171,227,229],{"class":173,"line":228},3,[171,230,232],{"class":231},"sU953","    \u002F\u002F Reference the existing Embedded Controller and its fields\n",[171,234,236,239],{"class":173,"line":235},4,[171,237,238],{"class":177},"    External",[171,240,241],{"class":181}," (\\_SB.PC00.LPCB.H_EC, DeviceObj)\n",[171,243,245,247],{"class":173,"line":244},5,[171,246,238],{"class":177},[171,248,249],{"class":181}," (\\_SB.PC00.LPCB.H_EC.FNSP, FieldUnitObj)\n",[171,251,253,255],{"class":173,"line":252},6,[171,254,238],{"class":177},[171,256,257],{"class":181}," (\\_SB.PC00.LPCB.H_EC.FNRV, FieldUnitObj)\n",[171,259,261,263],{"class":173,"line":260},7,[171,262,238],{"class":177},[171,264,265],{"class":181}," (\\_SB.PC00.LPCB.H_EC.MFNM, FieldUnitObj)\n",[171,267,269],{"class":173,"line":268},8,[171,270,272],{"emptyLinePlaceholder":271},true,"\n",[171,274,276,279],{"class":173,"line":275},9,[171,277,278],{"class":177},"    Scope",[171,280,281],{"class":181}," (\\_SB)\n",[171,283,285],{"class":173,"line":284},10,[171,286,287],{"class":181},"    {\n",[171,289,291,294],{"class":173,"line":290},11,[171,292,293],{"class":177},"        Device",[171,295,296],{"class":181}," (FNFX)\n",[171,298,300],{"class":173,"line":299},12,[171,301,302],{"class":181},"        {\n",[171,304,306,309,312,315,318],{"class":173,"line":305},13,[171,307,308],{"class":177},"            Name",[171,310,311],{"class":181}," (_HID, ",[171,313,314],{"class":185},"\"REAL0001\"",[171,316,317],{"class":181},")",[171,319,320],{"class":231}," \u002F\u002F Custom Hardware ID\n",[171,322,324],{"class":173,"line":323},14,[171,325,326],{"class":181},"            \n",[171,328,330],{"class":173,"line":329},15,[171,331,332],{"class":231},"            \u002F\u002F Runs once during ACPI initialization\n",[171,334,336,339,342,345],{"class":173,"line":335},16,[171,337,338],{"class":177},"            Method",[171,340,341],{"class":181}," (_INI, ",[171,343,344],{"class":196},"0",[171,346,347],{"class":181},", NotSerialized)\n",[171,349,351],{"class":173,"line":350},17,[171,352,353],{"class":181},"            {\n",[171,355,357,360,363],{"class":173,"line":356},18,[171,358,359],{"class":181},"                \\_SB.PC00.LPCB.H_EC.FNSP ",[171,361,362],{"class":212},"=",[171,364,365],{"class":196}," 0\n",[171,367,369,372,374],{"class":173,"line":368},19,[171,370,371],{"class":181},"                \\_SB.PC00.LPCB.H_EC.FNRV ",[171,373,362],{"class":212},[171,375,376],{"class":196}," 1\n",[171,378,380,383,385],{"class":173,"line":379},20,[171,381,382],{"class":181},"                \\_SB.PC00.LPCB.H_EC.MFNM ",[171,384,362],{"class":212},[171,386,365],{"class":196},[171,388,390],{"class":173,"line":389},21,[171,391,392],{"class":181},"            }\n",[171,394,396],{"class":173,"line":395},22,[171,397,398],{"class":181},"        }\n",[171,400,402],{"class":173,"line":401},23,[171,403,404],{"class":181},"    }\n",[171,406,408],{"class":173,"line":407},24,[171,409,410],{"class":181},"}\n",[150,412,414],{"id":413},"compile","Compile",[15,416,417,418,421,422,425],{},"Compile using ",[37,419,420],{},"iasl",", which produces ",[37,423,424],{},"fnfix.aml",".",[162,427,431],{"className":428,"code":429,"language":430,"meta":167,"style":167},"language-bash shiki shiki-themes github-light-default github-dark-default","iasl fnfix.dsl\n\n","bash",[37,432,433],{"__ignoreMap":167},[171,434,435,438],{"class":173,"line":174},[171,436,420],{"class":437},"sTDnQ",[171,439,440],{"class":185}," fnfix.dsl\n",[15,442,443],{},"Now package the AML the way the kernel expects it.",[162,445,447],{"className":428,"code":446,"language":430,"meta":167,"style":167},"mkdir -p kernel\u002Ffirmware\u002Facpi\ncp fnfix.aml kernel\u002Ffirmware\u002Facpi\u002F\nfind kernel | cpio -H newc -o > acpi_override.img\nsudo cp acpi_override.img \u002Fboot\u002F\n\n",[37,448,449,460,471,500],{"__ignoreMap":167},[171,450,451,454,457],{"class":173,"line":174},[171,452,453],{"class":437},"mkdir",[171,455,456],{"class":196}," -p",[171,458,459],{"class":185}," kernel\u002Ffirmware\u002Facpi\n",[171,461,462,465,468],{"class":173,"line":222},[171,463,464],{"class":437},"cp",[171,466,467],{"class":185}," fnfix.aml",[171,469,470],{"class":185}," kernel\u002Ffirmware\u002Facpi\u002F\n",[171,472,473,476,479,482,485,488,491,494,497],{"class":173,"line":228},[171,474,475],{"class":437},"find",[171,477,478],{"class":185}," kernel",[171,480,481],{"class":212}," |",[171,483,484],{"class":437}," cpio",[171,486,487],{"class":196}," -H",[171,489,490],{"class":185}," newc",[171,492,493],{"class":196}," -o",[171,495,496],{"class":212}," >",[171,498,499],{"class":185}," acpi_override.img\n",[171,501,502,505,508,511],{"class":173,"line":235},[171,503,504],{"class":437},"sudo",[171,506,507],{"class":185}," cp",[171,509,510],{"class":185}," acpi_override.img",[171,512,513],{"class":185}," \u002Fboot\u002F\n",[150,515,517],{"id":516},"load-it-before-the-main-initramfs","Load it before the main initramfs",[15,519,520,521,524],{},"We need to make sure that the ACPI image is the first ",[37,522,523],{},"initrd"," the bootloader loads, ahead of the normal initramfs.",[15,526,527],{},"Depending on the bootloader, we simply append it before the main image. For example:",[162,529,534],{"className":530,"code":532,"language":533,"meta":167},[531],"language-text","title   Linux\nlinux   \u002Fvmlinuz-linux\ninitrd  \u002Facpi_override.img\ninitrd  \u002Finitramfs-linux.img\noptions root=UUID=xxxx-xxxx-xxxx rw\n","text",[37,535,532],{"__ignoreMap":167},[15,537,538],{},"Finally, we can reboot.",[15,540,541,542,544,545,547],{},"The kernel loads the overlay, the dummy device's ",[37,543,136],{}," method runs during initialization, and the top row sends real F1-F12 events without needing to hold the ",[37,546,39],{}," key!",[549,550,551],"style",{},"html pre.shiki code .sTDnQ, html code.shiki .sTDnQ{--shiki-default:#953800;--shiki-dark:#FFA657}html pre.shiki code .sSVrQ, html code.shiki .sSVrQ{--shiki-default:#0A3069;--shiki-dark:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sHrmB, html code.shiki .sHrmB{--shiki-default:#0550AE;--shiki-dark:#79C0FF}html pre.shiki code .sjeE4, html code.shiki .sjeE4{--shiki-default:#CF222E;--shiki-dark:#FF7B72}html pre.shiki code .sbjLL, html code.shiki .sbjLL{--shiki-default:#8250DF;--shiki-dark:#D2A8FF}html pre.shiki code .s4rv2, html code.shiki .s4rv2{--shiki-default:#1F2328;--shiki-dark:#E6EDF3}html pre.shiki code .sU953, html code.shiki .sU953{--shiki-default:#6E7781;--shiki-dark:#8B949E}",{"title":167,"searchDepth":222,"depth":222,"links":553},[554,555,556,557],{"id":47,"depth":222,"text":48},{"id":68,"depth":222,"text":69},{"id":84,"depth":222,"text":85},{"id":140,"depth":222,"text":141,"children":558},[559,560,561],{"id":152,"depth":228,"text":153},{"id":413,"depth":228,"text":414},{"id":516,"depth":228,"text":517},"2026-08-10","Enabling Realme Book i5's top row send real F1–F12 keys by default on Linux, using a custom ACPI SSDT that flips the Fn mode at boot.","md",null,[567,568,569,570,571,572,573,574,97,575,420,576],"realme book i5","function keys","fn lock","f1-f12","linux","acpi","ssdt","acpi table override","embedded controller","laptop keyboard",{},"\u002Fblog\u002Fgetting-the-function-keys-back-on-a-realme-book-i5","index, follow","[object Object]",{"loc":578},"blog\u002Fgetting-the-function-keys-back-on-a-realme-book-i5","PxIELnGPg_E8TzIIVPWbzWwJfHXp9dGNGNwhQ-osnhA",[565,585],{"title":586,"path":587,"stem":588,"date":589,"children":-1},"Getting into the world of Ansible","\u002Fblog\u002Fgetting-into-the-world-of-ansible","blog\u002Fgetting-into-the-world-of-ansible","2026-05-23",1790255623091]