Screen Unresponsive on Ubuntu 20.04 but works on a Windows PC

Hi there, grateful for any assistance or pointers here.
I am running Ubuntu 20.04 LTS, Psychtoolbox 3.0.18.12 and Mesa Intel UHD Graphics CML GT2 on Matlab 2022b.
The task is fairly simple - a series of pictures are presented and the participant rates the valence of each. In the first screen you press the space bar to begin.
The task works on a colleague’s machine running Windows 10 and Intel graphics P630 but on my machine the keyboard is unresponsive - although the task can be exited by pressing “i” for some reason. I have run another Psychtoolbox task on this machine with no issues so I am confused as to why I have this problem. Is there some issue with Screen of Keybinding here?
Code below:

function ocd_task_rate_images_mri_phil(pcateg,pnpics)

% Enable unified mode of KbName, so KbName accepts identical key names on all operating systems:
KbName('UnifyKeyNames');
ex.ESCAPE = KbName('escape'); % key to exit experiment

%
% FUNCTION ocd_task_rate_images_03(mode,pcateg,pnpics)
%
% Runs the image rating task for the OCD trial.
% MODE: 'mri' or 'ephys' - controls stimulus timing.
% PCATEG: Specific picture category for this patient .
% PNPICS: Factor for how many images to use from this category (default is 2 for
%     twcie as many).
% Output is written to a .mat file (in the current folder) using the name of
% the function (eg ocd_task_rate_images) and the current date and time.

% TO DO
% done: keypresses '1' '2' with +/-5 level rating scale
% done: make sure results are saved after ESC
% done: select heaps of images, keep going until ESC
% done: optional blank fixation delay period between images
% done: add params as required
% choose 1 or more folders to pick extra images from
%
% FOR CLINICAL VERSION ENSURE:
%  - clinical_ready = true; % Set to true when ready for clinical use
%  - do_sync_test = false;  % Sync tests fail on MRI setup
%  - for ephys screennum = 0; mri = 2;
%  - rethrow(ALLERRS); % must be activated
%  - pause_every_ntrials = 40
%  - picdir is set correctly

% All these should be set to true for clinical use
clinical_ready = true; % Set to true when ready for clinical use
do_sync_test = true;  % Sync tests fail on MRI setup

% Params
nratesteps = 5;     % Num rating steps in each direction (up and down)
nloadimages = 200;  % How many images to load in total
totratesteps = nratesteps*2+1;
mode1 = 'm';
blanktime = 2;        % Blank period in sec between images
image_only_time = 2;  % Display image without rating bar for n secs
nulltime = 12;        % Blank screen for 12 secs after every 5th image
keytimeout = 2;       % 2 sec timeout after last keypress
bartimeout = 5;       % 5 sec timeout after rating bar appears
pause_after_sync = 5; % 5 secs pause after syncing
pause_every_ntrials = 40; % Pause and re-sync after every n images
screennum = 0; %1;
forecolr = [128 128 128];

% Image folder
picdir = 'IAPS-1-20-Images';

% Check other arguments
if nargin < 1; pcateg = ''; end
if nargin < 2; pnpics = 2; end

% New random seed
rand('twister',sum(100*clock()))

try
    % Not for when running real experiments
    if ~do_sync_test
        Screen('Preference','SkipSyncTests',1);
    else
        Screen('Preference','SkipSyncTests',0);
    end
    
    % Load category folders
    dirlist = dir(fullfile(picdir));
    % Remove any starting with . and also remove the patient specific folder
    di = 1;
    while di <= length(dirlist)
        if dirlist(di).name(1) == '.' || ~dirlist(di).isdir || strcmpi(dirlist(di).name,pcateg)
            dirlist(di) = [];
        else
            di = di + 1;
        end
    end
    
    % Load all the image names from each folder
    disp('Please wait... loading images');
    images = {};
    piclist = {};
    picfolder = {};
    for di = 1:length(dirlist)
        % Load the image names and then remove any starting with '.'
        fillist = dir(fullfile(picdir,dirlist(di).name,'*.jpg'));
        fi = 1;
        while fi <= length(fillist)
            if fillist(fi).name(1) == '.'; fillist(fi) = [];
            else fi = fi + 1;
            end
        end
        for ii = 1:length(fillist)
            piclist{end+1} = fillist(ii).name;
            picfolder{end+1} = dirlist(di).name;
        end
    end
    totpic_norm = length(piclist); % Num normal pics
    % Load extra image names from the patient specific folder
    if ~isempty(pcateg)
        fillist = dir(fullfile(picdir,pcateg,'*.jpg'));
        if isempty(fillist)
            error(['Folder ' pcateg ' does not exist']);
        end
        fi = 1;
        while fi <= length(fillist)
            if fillist(fi).name(1) == '.'; fillist(fi) = [];
            else fi = fi + 1;
            end
        end
        for ii = 1:length(fillist)
            piclist{end+1} = fillist(ii).name;
            picfolder{end+1} = pcateg;
        end
    end
    totpic_subj = length(piclist)-totpic_norm; % Num subject-specific pics
    
    % Now choose images 'randomly'
    if totpic_subj > 0
        nsubjpics = ceil(nloadimages/length(dirlist)*pnpics);
    else
        nsubjpics = 0;
        pnpics = 0;
    end
    if totpic_subj < nsubjpics
        error(['Too few images in patient-specific folder ' fullfile(picdir,pcateg)]);
    end
    % Choose pics in groups of length equal to the number of categories to
    % make sure that patient specific images are 'evenly but randomly' spread
    picorder = [];
    normi = 0;
    subji = 0;
    rp_norm = randperm(totpic_norm);
    rp_subj = randperm(totpic_subj);
    while length(images) < nloadimages
        rp_loop = randperm(length(dirlist)+ceil(pnpics));
        for i = 1:length(rp_loop)
            if rp_loop(i) <= length(dirlist)
                normi = normi + 1;
                picorder(end+1) = rp_norm(normi);
            else
                subji = subji + 1;
                picorder(end+1) = totpic_norm + rp_subj(subji);
            end
            images{end+1} = imread(fullfile(picdir,picfolder{picorder(end)},piclist{picorder(end)}));
        end
    end
    disp('Done.');
    drawnow();
    
    
	% Open a window
	[window,winrect] = Screen(screennum,'OpenWindow');
	WaitSecs(1);
    wc = winrect(3:4)/2;   % window centre
        
    
    % Set default text properties
    Screen('TextSize',window,25);
    Screen('TextFont',window,'Helvetica');
    if clinical_ready
        HideCursor();
    end
    
    % Rating bar dimensions - first the outline and then the bar itself
    boutrect = [winrect(3)*0.093,winrect(4)*0.14,winrect(3)*0.907,winrect(4)*0.21];
    brect = [winrect(3)*0.1,winrect(4)*0.15,winrect(3)*0.9,winrect(4)*0.2];
    blen = brect(3)-brect(1);

    % Banner until SPACE BAR
    Screen('FillRect',window,[0 0 0]);
    Screen('DrawText',window,'OCD Image Rating (OCDIR) Task',winrect(3)*0.2,winrect(4)*0.4,forecolr);
    if ~clinical_ready
        Screen('DrawText',window,'Demonstration only. Not for Clinical use.',winrect(3)*0.2,winrect(4)*0.5,[255 0 0]);
    end
    Screen('DrawText',window,'Press SPACE to continue',winrect(3)*0.2,winrect(4)*0.7,forecolr/2);
    Screen(window,'Flip'); kidx = zeros(1,256); while ~(kidx(27)||kidx(32)); [~,kidx] = KbPressWait(); end % Wait for SPACE
    if kidx(27); ShowCursor(); Screen('CloseAll'); return; end % Check for ESC key
    
    % Instructions
    Screen('FillRect',window,[0 0 0]);
    DrawFormattedText(window,['INSTRUCTIONS:\n\n1. Look at each image.\n\n'...
        '2. Rate the image by clicking buttons to control the bar at the top of the screen.\n'],'center','center',forecolr,75,[],[],1.5);
    Screen('DrawText',window,'Press SPACE to continue',winrect(3)*0.2,winrect(4)*0.7,forecolr/2);
    Screen(window,'Flip'); kidx = zeros(1,256); while ~(kidx(27)||kidx(32)); [~,kidx] = KbPressWait(); end % Wait for SPACE
    if kidx(27); ShowCursor(); Screen('CloseAll'); return; end % Check for ESC key
    
    % Clear image rating and response times
    test_rating = [];
    test_clicktime = [];
    test_timing = zeros(0,3);
    kidx = zeros(1,256);
    
    % Loop thru images
    totnimages = length(images); %length(textures)
    imgn = 0;
    while imgn < totnimages
        % SYNC with MRI
        esckey = sync_mri();
        if esckey; ShowCursor(); Screen('CloseAll'); break; end % Check for ESC key
        
        % Loop thru this block of images
        lastloop = min(imgn+pause_every_ntrials,totnimages);
        for imgn = imgn+1:lastloop
            disp(sprintf('Image %d/%d',imgn,totnimages));

            % Fixation cross if wanted
            if blanktime > 0
                % Display cross for trial start duration
                Screen('FillRect',window,[0 0 0]);
                Screen('DrawLine',window,forecolr,wc(1),wc(2)+100,wc(1),wc(2)-100,10);
                Screen('DrawLine',window,forecolr,wc(1)-100,wc(2),wc(1)+100,wc(2),10);
                Screen(window,'Flip'); WaitSecs(blanktime);
            end

            % Display image and wait for 2 secs
            texture = Screen('MakeTexture',window,images{imgn});
            Screen('FillRect',window,[0 0 0]);
            Screen('DrawTexture',window,texture); %textures{ceil(rand()*length(textures))});
            Screen(window,'Flip',[],1); test_timing(imgn,1) = GetSecs();
            WaitSecs(image_only_time);

            % Display rating bar - first the outline
            Screen('FillRect',window,forecolr/2,boutrect);
            for bstp = 1:totratesteps
                srect = [brect(1)+(bstp-1)*blen/totratesteps,brect(2),brect(1)+bstp*blen/totratesteps,brect(4)];
                if bstp <= nratesteps+1
                    Screen('FillRect',window,[255 255*(bstp)/(nratesteps+1) 255*(bstp)/(nratesteps+1)],srect);
                else
                    Screen('FillRect',window,[255*(totratesteps-bstp)/nratesteps 255 255*(totratesteps-bstp)/nratesteps],srect);
                end
            end
            % Current rating in the centre
            ratepos = nratesteps+1;

            % Now move the rating selection box based on the keypress
            bardisptim = GetSecs();
            lastkeytim = bardisptim;
            kidx(32) = 1;
            while any(kidx~=0)
                % Redraw the current rating in its proper colour
                srect = [brect(1)+(ratepos-1)*blen/totratesteps,brect(2),brect(1)+ratepos*blen/totratesteps,brect(4)];
                if ratepos <= nratesteps+1
                    Screen('FillRect',window,[255 255*(ratepos)/(nratesteps+1) 255*(ratepos)/(nratesteps+1)],srect);
                else
                    Screen('FillRect',window,[255*(totratesteps-ratepos)/nratesteps 255 255*(totratesteps-ratepos)/nratesteps],srect);
                end
                % Process keypress
                if kidx(49)
                    % Move left
                    ratepos = max(ratepos-1,1);
                    lastkeytim = GetSecs();
                elseif kidx(50)
                    % Move right
                    ratepos = min(ratepos+1,totratesteps);
                    lastkeytim = GetSecs();
                end
                % Redraw the current rating in the selection colour
                srect = [brect(1)+(ratepos-1)*blen/totratesteps,brect(2),brect(1)+ratepos*blen/totratesteps,brect(4)];
                Screen('FrameRect',window,[0 0 0],srect,5);
                Screen(window,'Flip',[],1);
                % Get next keypress with a timeout
                [test_timing(imgn,3), kidx] = KbPressWait([],min(lastkeytim+keytimeout,bardisptim+bartimeout));
                if kidx(27); imgn = imgn-1; break; end % Check for ESC key
                if test_timing(imgn,2) == 0
                    test_timing(imgn,2) = test_timing(imgn,3);
                end
            end
            if kidx(27); break; end % Check for ESC key

            % Calculate response
            timing_sync = 0
            test_timing(imgn,2:3) = test_timing(imgn,2:3) - keytimeout;
            test_timing(imgn,:) = test_timing(imgn,:) - timing_sync;
            test_clicktime(imgn) = (test_timing(imgn,2)-test_timing(imgn,1))*1000; % click time in ms
            %test_rating(imgn) = max(min((mx-brect(1)-blen/2)/(blen/2),1),-1);      % Subject rating in [-1,1]
            test_rating(imgn) = (ratepos-1-nratesteps)/nratesteps;      % Subject rating in [-1,1]
            
            % Close texture
            Screen('Close',texture);
            
            % NULL trial every 5 images
            if mod(imgn,5)==0 && imgn~=lastloop
                Screen('FillRect',window,[0 0 0]);
%                 Screen('DrawLine',window,forecolr,wc(1),wc(2)+100,wc(1),wc(2)-100,10);
%                 Screen('DrawLine',window,forecolr,wc(1)-100,wc(2),wc(1)+100,wc(2),10);
                Screen(window,'Flip'); WaitSecs(nulltime);
            end
        end
        
        % Wait for SPACE BAR
        if imgn < totnimages
            Screen('FillRect',window,[0 0 0]); Screen(window,'Flip'); % Blank screen
            disp('PAUSED for rest. Press SPACE BAR to continue');
            kidx = zeros(1,256); while ~(kidx(27)||kidx(32)); [~,kidx] = KbPressWait(); end % Wait for SPACE
            esckey = kidx(27); if esckey; break; end % Check for ESC key
            disp('Continuing');
        end
    end
    
    % Save all the data
    test_timing = test_timing;
    piclist = piclist(picorder); % Re-order image names into presentation order
    picfolder = picfolder(picorder);
    savnam = [mfilename() '_' datestr(now(),30)];
    save(savnam,'totnimages','imgn','piclist','picfolder','picorder','test_clicktime',...
        'test_rating','test_timing','nratesteps','keytimeout','clinical_ready','do_sync_test',...
        'screennum','picdir','totratesteps','blanktime','mode1','pcateg','pnpics');
    disp(['Results saved to ' savnam '.mat']);

    % Finished
    ShowCursor();
    Screen('CloseAll');

    % Show reaction times etc
    if ~clinical_ready
        figure; subplot(2,1,1); plot(test_clicktime), xlabel('Trial #'); ylabel('Reaction time (ms)'); title('Reaction times');
        subplot(2,1,2); plot(test_rating); ylim([-1 1]); xlabel('Trial #'); ylabel('Rating (-1 - 1)'); title('Image rating');
        figure; plot(test_rating,(test_clicktime),'.'); xlabel('Rating'); ylabel('Click time');
    end
    
catch ALLERRS
    Screen('CloseAll');
    ShowCursor;
    Priority(0);
    disp('ERROR catch');
    rethrow(ALLERRS);
    %keyboard;
    %psychrethrow(psychlasterror);
end

    %---------------------------------------------------------
    % SYNC with MRI
    %
    function esckey = sync_mri()
        % SYNC PULSE TIMING
        Screen('FillRect',window,[0 0 0]); Screen(window,'Flip',[],1); % Blank screen
        GetSecs(); timing_sync = 0; % make sure tic function and variable are in mem
        disp('');
        disp('Waiting for MRI sync signal ''5''.');
        disp('SEND SYNC PULSE to continue'); drawnow();
        esckey = 0;
        kidx = zeros(1,256);
        while ~kidx(53)
            [~,~,kidx] = KbCheck; esckey = kidx(27); if esckey; return; end % Check for ESC key
        end
        timing_sync = GetSecs(); % Sync received
        disp('SYNC received!');
        % Pause for a bit
        disp(['Pausing for ' num2str(pause_after_sync) ' secs...']);  drawnow();
        WaitSecs(pause_after_sync);
        disp('Pause complete, continuing...');
    end

end

Thank you again. Phil

The mystery of pressing i is there. kidx(32) is i on Linux but it is space on Windows. You should check the key codes are being properly specified. You should also make sure you call KbName('UnifyKeyNames') so each OS uses the same codes.

In general it is much more readable to explicitly use KbName to define keycodes then use these named variables:

KbName('UnifyKeyNames')
continueKey = KbName('space');
while true
    [~,kidx] = KbPressWait();
    if any(kidx(continueKey)); break; end
end

Thank you so much for your pointer. I really appreciate your help!!! It is running now as intended. Best, Phil